QuiLayout 布局
QuiLayout 是一个基于 Naive UI 的高度可配置的布局组件,提供了多种常见的后台管理系统布局模式,并集成了路由菜单自动生成、面包屑导航、动态路由管理等功能。
基础用法
1. 定义布局存储
推荐使用 Pinia 来管理布局状态,利用 useLayout 组合式函数初始化布局配置。
ts
// stores/layout.ts
import { defineStore } from 'pinia'
import { useLayout } from '@quiteer/naive-extra'
import router, { routes } from '@/router'
export const useLayoutStore = defineStore('layout', () => {
const {
collapsed,
activeKey,
menuOptions,
type,
baseRoutes,
addRoute,
removeRoute,
// ...其他状态
} = useLayout({
baseRoutes: routes,
router,
initialActiveKey: '/',
type: 'side-menu', // 默认布局类型
// ...其他配置
})
return {
collapsed,
activeKey,
menuOptions,
type,
baseRoutes,
addRoute,
removeRoute,
// ...
}
})2. 使用组件
在你的应用主布局文件中引入 QuiLayout 并绑定状态。
vue
<!-- layout/index.vue -->
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { QuiLayout } from '@quiteer/naive-extra'
import { useLayoutStore } from '@/stores/layout'
const layoutStore = useLayoutStore()
const {
collapsed,
activeKey,
menuOptions,
type,
baseRoutes,
inverted,
bordered,
headerHeight,
footerHeight,
siderWidth,
collapsedWidth
} = storeToRefs(layoutStore)
</script>
<template>
<QuiLayout
v-model:is-collapsed="collapsed"
v-model:active-key="activeKey"
v-model:inverted="inverted"
:type="type"
:base-routes="baseRoutes"
:menu-options="menuOptions"
:bordered="bordered"
:header-height="headerHeight"
:footer-height="footerHeight"
:sider-width="siderWidth"
:collapsed-width="collapsedWidth"
/>
</template>布局模式 (Layout Types)
QuiLayout 支持多种布局模式,通过 type 属性进行切换。
| 类型 | 名称 | 描述 |
|---|---|---|
side-menu | 左侧菜单布局 | 左侧菜单布局,左侧为垂直导航菜单,右侧为主内容区 |
side-menu/2 | 左侧-顶部菜单布局 | 左侧为垂直导航菜单,顶部为水平导航菜单,下方为主内容区 |
side-mixed-menu/2 | 左侧混合-顶部菜单布局 | 左侧为垂直导航菜单,顶部为水平导航菜单,下方为主内容区 |
top-menu | 顶部菜单布局 | 无侧边栏,顶部为水平导航菜单,下方为主内容区 |
top-menu/2 | 顶部-左侧菜单布局 | 顶部菜单为主,顶部为水平导航菜单,左侧为垂直导航菜单,下方为主内容区 |
top-mixed-menu/2 | 顶部-左侧混合菜单布局 | 顶部菜单为主,顶部为水平导航菜单,左侧为垂直导航菜单,下方为主内容区 |
blank | 无菜单布局 | 无菜单布局,页面不包含任何主导航菜单,适用于登录页、引导页、全屏应用等场景 |
注意:带
/2后缀的混合模式支持双菜单联动(Main Menu & Sub Menu),组件内部会自动处理activeKey的同步与解析,实现一级菜单与二级菜单的分离展示与联动。
API 参考
QuiLayout Props
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
type | LayoutType | 'side-menu' | 布局类型 |
baseRoutes | RouteRecordRaw[] | [] | 基础路由表,用于生成菜单 |
menuOptions | MenuOption[] | [] | 菜单选项数据 |
activeKey | string | '/' | 当前激活的菜单 Key (v-model) |
isCollapsed | boolean | false | 侧边栏是否折叠 (v-model) |
inverted | boolean | false | 是否反色主题 (v-model) |
bordered | boolean | true | 是否显示边框 |
headerHeight | number | 54 | 头部高度 |
footerHeight | number | 42 | 底部高度 |
footerFull | boolean | true | 底部是否占满宽度 |
showFooter | boolean | true | 是否显示底部 |
siderWidth | number | 220 | 侧边栏宽度 |
siderMixedWidth | number | 80 | 侧边栏混合模式宽度 |
collapsedWidth | number | 60 | 侧边栏折叠后宽度 |
accordion | boolean | true | 是否开启手风琴模式 |
默认配置
QuiLayout 默认值(来自 DEFAULT_LAYOUT_PROPS):
ts
{
type: 'side-menu',
bordered: true,
inverted: false,
isCollapsed: false,
showFooter: true,
headerHeight: 54,
footerHeight: 42,
footerFull: true,
siderWidth: 220,
siderMixedWidth: 80,
collapsedWidth: 60,
activeKey: '/',
menuOptions: [],
accordion: true
}useLayout 返回值
useLayout 提供了布局所需的状态管理和工具方法。
| 属性/方法 | 类型 | 说明 |
|---|---|---|
activeKey | Ref<string> | 当前激活的路由路径 |
setActiveKey | (key: string) => void | 设置激活路径 |
collapsed | Ref<boolean> | 侧边栏折叠状态 |
setCollapsed | (v: boolean) => void | 设置折叠状态 |
toggle | () => void | 切换折叠状态 |
type | Ref<LayoutType> | 当前布局类型 |
menuOptions | ComputedRef<MenuOption[]> | 根据路由生成的菜单选项 |
addRoute | (route: RouteRecordRaw) => void | 动态添加路由,并自动更新菜单 |
removeRoute | (name: string) => void | 动态移除路由 |
addRoutes | (routes: RouteRecordRaw[]) => void | 批量添加路由 |
useLayout 参数
| 参数 | 类型 | 说明 |
|---|---|---|
baseRoutes | RouteRecordRaw[] | Ref<RouteRecordRaw[]> | 基础路由表 |
router | Router | 显式传入路由实例,确保在 Store 中可用 |
route | RouteLocationNormalizedLoaded | 可选,显式传入当前路由 |
menuOptions | MenuOption[] | Ref<MenuOption[]> | 菜单数据,传入后优先使用 |
initialActiveKey | string | 初始激活菜单 key |
type | LayoutType | 布局类型 |
动态路由管理
QuiLayout 深度集成了 vue-router,通过 useLayout 提供的 addRoute 和 removeRoute 方法,可以轻松实现动态路由的添加与删除,且菜单会自动更新。
添加路由示例
ts
const { addRoute } = useLayoutStore()
function addDynamicPage() {
addRoute({
path: '/dynamic-page',
name: 'DynamicPage',
meta: {
title: '动态页面',
icon: 'mdi:flash'
},
component: () => import('@/pages/DynamicPage.vue')
})
}移除路由示例
ts
const { removeRoute } = useLayoutStore()
function removeDynamicPage() {
removeRoute('DynamicPage')
}功能特性
- 自动菜单生成:根据传入的
baseRoutes自动生成符合 Naive UI 格式的菜单选项。 - 面包屑导航:在
side-menu等模式下自动生成面包屑。 - 布局切换联动:在单栏菜单(如
side-menu)与双栏菜单(如top-mixed-menu/2)切换时,自动解析并同步activeKey,保持选中状态一致。 - 响应式适配:支持配置侧边栏宽度、头部高度等尺寸。
- Vue Router 同步:
activeKey会自动跟随路由变化,点击菜单也会自动触发路由跳转。