Vuetify嵌套v-expansion-panels实现多层侧边菜单问题求助
实现Vuetify多层嵌套的展开面板(层级侧边菜单)
要实现带多层子项的层级侧边菜单,核心是嵌套使用v-expansion-panels和v-expansion-panel-item,配合缩进样式区分层级。以下是直接可用的实现方案:
方案1:静态嵌套(适合固定层级)
如果菜单层级固定(比如最多3层),直接嵌套写死即可,代码清晰易维护:
<template> <!-- 根级展开面板 --> <v-expansion-panels accordion dense class="sidebar-menu"> <!-- 一级菜单 --> <v-expansion-panel-item v-for="(topItem, idx) in menuData" :key="idx" > <!-- 自定义一级菜单头部 --> <template v-slot:header> <div class="d-flex align-center"> <v-icon class="mr-2">{{ topItem.icon || 'mdi-folder' }}</v-icon> <span>{{ topItem.title }}</span> </div> </template> <!-- 二级菜单面板 --> <v-expansion-panels v-if="topItem.children" accordion dense class="ml-6"> <v-expansion-panel-item v-for="(secondItem, sIdx) in topItem.children" :key="sIdx" > <template v-slot:header> <div class="d-flex align-center"> <v-icon class="mr-2">{{ secondItem.icon || 'mdi-folder-outline' }}</v-icon> <span>{{ secondItem.title }}</span> </div> </template> <!-- 三级菜单面板 --> <v-expansion-panels v-if="secondItem.children" accordion dense class="ml-6"> <v-expansion-panel-item v-for="(thirdItem, tIdx) in secondItem.children" :key="tIdx" > <template v-slot:header> <div class="d-flex align-center"> <v-icon class="mr-2">{{ thirdItem.icon || 'mdi-file-document-outline' }}</v-icon> <span>{{ thirdItem.title }}</span> </div> </template> <!-- 若有更多层级,继续嵌套即可 --> </v-expansion-panel-item> </v-expansion-panels> </v-expansion-panel-item> </v-expansion-panels> </v-expansion-panel-item> </v-expansion-panels> </template> <script> export default { data() { return { menuData: [ { title: '系统管理', icon: 'mdi-cog', children: [ { title: '用户管理', children: [ { title: '用户列表' }, { title: '角色分配' } ] }, { title: '权限配置' } ] }, { title: '内容运营', icon: 'mdi-file-document', children: [ { title: '文章管理' }, { title: '分类管理', children: [{ title: '分类列表' }, { title: '分类排序' }] } ] } ] } } } </script> <style scoped> /* 调整菜单紧凑度,适配侧边栏 */ .sidebar-menu .v-expansion-panel-header { padding: 8px 16px !important; } </style>
方案2:递归组件(支持无限层级)
如果菜单层级不固定,把嵌套逻辑抽成递归组件更灵活:
1. 创建递归组件 MenuPanel.vue
<template> <v-expansion-panels accordion dense> <v-expansion-panel-item v-for="(item, idx) in items" :key="idx" > <template v-slot:header> <!-- 根据层级动态缩进 --> <div class="d-flex align-center" :style="{ paddingLeft: `${16 + 24 * level}px` }"> <v-icon class="mr-2">{{ getIcon(item) }}</v-icon> <span>{{ item.title }}</span> </div> </template> <!-- 递归渲染子菜单 --> <MenuPanel v-if="item.children && item.children.length" :items="item.children" :level="level + 1" /> </v-expansion-panel-item> </v-expansion-panels> </template> <script> export default { name: 'MenuPanel', // 必须命名,递归组件需要 props: { items: { type: Array, required: true }, level: { type: Number, default: 0 // 初始层级为0(根菜单) } }, methods: { getIcon(item) { // 根据是否有子项自动分配图标 return item.children ? 'mdi-folder' : 'mdi-file-document-outline' } } } </script> <style scoped> .v-expansion-panel-header { padding: 8px 0 !important; } </style>
2. 在父组件中使用
<template> <div class="sidebar-menu"> <MenuPanel :items="menuData" /> </div> </template> <script> import MenuPanel from './MenuPanel.vue' export default { components: { MenuPanel }, data() { return { menuData: [ // 同之前的菜单数据,支持任意层级嵌套 ] } } } </script>
关键注意点
- 缩进样式:用Vuetify的
ml-*工具类(静态嵌套)或动态计算padding(递归组件)区分层级,匹配目标截图的视觉效果 - Accordion模式:开启
accordion属性,确保同一层级只能展开一个面板,符合侧边菜单交互习惯 - 自定义头部:通过
v-slot:header给每个菜单添加图标、调整布局,让样式更贴近目标截图
内容的提问来源于stack exchange,提问作者young_dev
相关产品推荐
相关产品推荐

