Appearance
BizLayout 布局壳
中后台主框架三段式:侧栏(递归菜单 + 折叠 220↔64 + logo 槽)、顶栏(折叠按钮 + 面包屑槽 + 右侧操作槽——通知 / 主题切换 / 用户区常用位)、内容区(默认滚动)。tabs 槽对接 BizTabsNav 即组成多页签框架。组件不绑路由:菜单点击 select(key) 由业务侧 router.push 接管。
基础用法
3
管 内容区:/dashboard 页面渲染在这里(默认滚动、带内边距)
v-model:collapsed 折叠侧栏;header-right 槽组合通知角标 / 主题切换 / 头像。<script setup lang="ts">
/** 基础用法:侧栏菜单 + 顶栏 + 内容区(select 事件接管路由跳转) */
import { ref } from 'vue'
import { ElMessage, ElBadge, ElAvatar } from 'element-plus'
import { Bell, Odometer, Goods, Setting, User, Files } from '@element-plus/icons-vue'
import { BizLayout, BizThemeSwitch } from 'vue3-ep-biz-lib'
import type { BizLayoutMenuItem } from 'vue3-ep-biz-lib'
const collapsed = ref(false)
const activeKey = ref('/dashboard')
const menus: BizLayoutMenuItem[] = [
{ key: '/dashboard', title: '工作台', icon: Odometer },
{ key: '/goods', title: '商品管理', icon: Goods, children: [
{ key: '/goods/list', title: '商品列表' },
{ key: '/goods/category', title: '分类管理' },
] },
{ key: '/orders', title: '订单中心', icon: Files },
{ key: '/users', title: '用户管理', icon: User },
{ key: '/settings', title: '系统设置', icon: Setting },
]
const onSelect = (key: string): void => {
activeKey.value = key
// 实际项目:router.push(key)
ElMessage.info(`导航到 ${key}(实际项目 router.push)`)
}
</script>
<template>
<div class="layout-demo">
<BizLayout
v-model:collapsed="collapsed"
:menus="menus"
:active-key="activeKey"
@select="onSelect"
title="运营平台"
:openeds="['/goods']"
>
<template #header-right>
<ElBadge :value="3">
<ElIcon :size="18"><Bell /></ElIcon>
</ElBadge>
<BizThemeSwitch storage-key="" />
<ElAvatar :size="28">管</ElAvatar>
</template>
<div style="padding: 24px; background: var(--el-bg-color); border-radius: 6px">
内容区:{{ activeKey }} 页面渲染在这里(默认滚动、带内边距)
</div>
</BizLayout>
</div>
</template>
<style scoped>
.layout-demo {
height: 420px;
border: 1px solid var(--el-border-color);
border-radius: var(--el-border-radius-base);
overflow: hidden;
}
.layout-demo :deep(.biz-layout__menu) {
height: calc(100% - 50px);
}
</style>
显示代码
多页签框架
首页
经营日报
多页签框架:tabs 槽接 BizTabsNav,菜单与页签联动(keep-alive 由业务路由层接管)
tabs 槽对接 BizTabsNav,菜单与页签联动(keep-alive 由业务路由层接管,见 BizTabsNav 文档)。<script setup lang="ts">
/** 进阶:tabs 槽对接 BizTabsNav 组成多页签主框架 + footer 槽 */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { DataLine, PieChart } from '@element-plus/icons-vue'
import { BizLayout, BizTabsNav } from 'vue3-ep-biz-lib'
import type { BizLayoutMenuItem, BizTabsNavItem } from 'vue3-ep-biz-lib'
const active = ref('/home')
const tabs = ref<BizTabsNavItem[]>([
{ key: '/home', title: '首页', affix: true, closable: false },
{ key: '/report', title: '经营日报' },
])
const menus: BizLayoutMenuItem[] = [
{ key: '/home', title: '首页', icon: PieChart },
{ key: '/report', title: '报表中心', icon: DataLine },
]
const onSelect = (key: string): void => {
active.value = key
if (!tabs.value.some((t) => t.key === key)) {
tabs.value = [...tabs.value, { key, title: menus.find((m) => m.key === key)?.title ?? key }]
}
}
const onTabChange = (key: string | number): void => {
// 实际项目:router.push(String(key))
ElMessage.info(`切到 ${key}`)
}
</script>
<template>
<div class="layout-demo">
<BizLayout :menus="menus" :active-key="String(active)" title="数据平台" @select="onSelect">
<template #tabs>
<BizTabsNav v-model="active" v-model:tabs="tabs" style="padding: 0 8px" @change="onTabChange" />
</template>
<template #footer>
© 2026 数据平台 · footer 插槽
</template>
<div style="padding: 24px; background: var(--el-bg-color); border-radius: 6px">
多页签框架:tabs 槽接 BizTabsNav,菜单与页签联动(keep-alive 由业务路由层接管)
</div>
</BizLayout>
</div>
</template>
<style scoped>
.layout-demo {
height: 420px;
border: 1px solid var(--el-border-color);
border-radius: var(--el-border-radius-base);
overflow: hidden;
}
</style>
显示代码
侧栏底部(退出登录)
side-footer 槽:版本号 + 退出登录常驻位(内网系统标配)。
<script setup lang="ts">
/** side-footer 槽:版本号 + 退出登录(侧栏底部常驻位) */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { SwitchButton } from '@element-plus/icons-vue'
import { BizLayout } from 'vue3-ep-biz-lib'
const active = ref('/home')
const menus = [
{ key: '/home', title: '首页' },
{ key: '/data', title: '数据看板' },
]
const logout = (): void => {
ElMessage.warning('退出登录(清理 token 后跳登录页)')
}
</script>
<template>
<div class="demo">
<BizLayout :menus="menus" :active-key="active" title="运维平台" @select="(k) => (active = k)">
<template #side-footer>
<div class="side-foot">
<span class="ver">v2.4.1 · 内网版</span>
<span class="logout" @click="logout">
<ElIcon><SwitchButton /></ElIcon> 退出登录
</span>
</div>
</template>
内容区
</BizLayout>
</div>
</template>
<style scoped>
.demo {
height: 380px;
border: 1px solid var(--el-border-color);
border-radius: var(--el-border-radius-base);
overflow: hidden;
}
.side-foot {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 16px;
font-size: 12px;
color: rgba(255, 255, 255, 0.55);
}
.logout {
display: inline-flex;
align-items: center;
gap: 4px;
cursor: pointer;
}
.logout:hover {
color: #fff;
}
</style>
显示代码
面包屑与用户区
首页/商品列表/
商
breadcrumb 槽嵌 el-breadcrumb;header-right 用户区。
<script setup lang="ts">
/** 面包屑槽:header 内嵌 el-breadcrumb + 右侧用户区 */
import { computed, ref } from 'vue'
import { BizLayout } from 'vue3-ep-biz-lib'
const active = ref('/goods/list')
const menus = [
{ key: '/goods', title: '商品管理' },
{ key: '/goods/list', title: '商品列表' },
{ key: '/goods/review', title: '资质审核' },
]
const crumb = computed(() => {
const hit = menus.find((m) => m.key === active.value)
return ['首页', hit?.title ?? '']
})
</script>
<template>
<div class="demo">
<BizLayout :menus="menus" :active-key="active" title="商家后台" @select="(k) => (active = k)">
<template #breadcrumb>
<ElBreadcrumb separator="/">
<ElBreadcrumbItem v-for="(item, i) in crumb" :key="i">{{ item }}</ElBreadcrumbItem>
</ElBreadcrumb>
</template>
<template #header-right>
<ElAvatar :size="28">商</ElAvatar>
</template>
当前页:{{ active }}
</BizLayout>
</div>
</template>
<style scoped>
.demo {
height: 380px;
border: 1px solid var(--el-border-color);
border-radius: var(--el-border-radius-base);
overflow: hidden;
}
</style>
显示代码
手风琴多级菜单
unique-opened 一次只展开一组 + openeds 预展开。
<script setup lang="ts">
/** 手风琴菜单:unique-opened + 预展开(多级导航收纳) */
import { ref } from 'vue'
import { Goods, Setting, DataLine } from '@element-plus/icons-vue'
import { BizLayout } from 'vue3-ep-biz-lib'
const active = ref('/goods/list')
const menus = [
{ key: '/goods', title: '商品中心', icon: Goods, children: [
{ key: '/goods/list', title: '商品列表' },
{ key: '/goods/category', title: '分类管理' },
{ key: '/goods/review', title: '资质审核' },
] },
{ key: '/data', title: '数据中心', icon: DataLine, children: [
{ key: '/data/report', title: '经营日报' },
{ key: '/data/live', title: '实时大屏' },
] },
{ key: '/settings', title: '系统设置', icon: Setting },
]
</script>
<template>
<div class="demo">
<BizLayout
:menus="menus"
:active-key="active"
title="控制台"
unique-opened
:openeds="['/goods']"
@select="(k) => (active = k)"
>
当前页:{{ active }}(一次只展开一个二级菜单)
</BizLayout>
</div>
</template>
<style scoped>
.demo {
height: 380px;
border: 1px solid var(--el-border-color);
border-radius: var(--el-border-radius-base);
overflow: hidden;
}
</style>
显示代码
大屏定制
指标模块 1
指标模块 2
指标模块 3
指标模块 4
指标模块 5
指标模块 6
side-width=260 + --biz-layout-body-padding: 0 内容区全出血(指挥大屏)。
<script setup lang="ts">
/** css 变量定制:侧栏 260 / 内边距 0(内容区全出血大屏) */
import { ref } from 'vue'
import { Monitor } from '@element-plus/icons-vue'
import { BizLayout } from 'vue3-ep-biz-lib'
const active = ref('/screen')
const menus = [
{ key: '/screen', title: '指挥大屏', icon: Monitor },
{ key: '/map', title: '一张图' },
]
</script>
<template>
<div class="demo" style="--biz-layout-body-padding: 0px">
<BizLayout :menus="menus" :active-key="active" :side-width="260" title="城市运行指挥中心" @select="(k) => (active = k)">
<div class="screen">
<div v-for="i in 6" :key="i" class="cell">指标模块 {{ i }}</div>
</div>
</BizLayout>
</div>
</template>
<style scoped>
.demo {
height: 380px;
border: 1px solid var(--el-border-color);
border-radius: var(--el-border-radius-base);
overflow: hidden;
}
.screen {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1px;
height: 100%;
background: var(--el-border-color-lighter);
}
.cell {
display: flex;
align-items: center;
justify-content: center;
background: var(--el-fill-color-light);
font-size: 13px;
color: var(--el-text-color-secondary);
}
</style>
显示代码
Props
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| menus | BizLayoutMenuItem[] | [] | 菜单树(递归;icon 支持组件 / 字体 class) |
| active-key / v-model:active-key | string | '' | 激活菜单 key(default-active) |
| openeds | string[] | [] | 默认展开的子菜单 |
| collapsed / v-model:collapsed | boolean | false | 侧栏折叠 |
| side-width | number | 220 | 侧栏宽度(折叠后 64) |
| header-height | number | 50 | 顶栏高度 |
| title | string | '管理系统' | logo 区标题(折叠时隐藏) |
| unique-opened | boolean | false | 子菜单手风琴模式 |
高度经 css 变量
--biz-layout-height(默认 100vh)、内容内边距--biz-layout-body-padding(默认 16px)调整。
Events
| 事件名 | 参数 | 说明 |
|---|---|---|
| update:collapsed | (value: boolean) | 折叠变化 |
| select | (key, item) | 菜单点击(路由跳转由业务侧接管) |
Slots
| 插槽名 | 说明 |
|---|---|
| — | 内容区 |
| logo | 侧栏 logo 区 |
| side-footer | 侧栏底部(如退出登录) |
| header | 顶栏中部(缺省渲染 breadcrumb 槽) |
| breadcrumb | 面包屑 |
| header-right | 顶栏右侧操作区 |
| tabs | 页签栏位(对接 BizTabsNav) |
| footer | 页脚 |
Expose
| 属性/方法 | 说明 |
|---|---|
| — | 无 |