You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 15:12:03