vue动态菜单实现
Vue 动态菜单实现
数据驱动菜单结构
动态菜单的核心是通过数据驱动渲染。通常从后端接口获取菜单数据,存储为数组或树形结构。例如:
// 示例菜单数据结构
const menuData = [
{
id: 1,
name: "首页",
path: "/home",
icon: "el-icon-house",
children: []
},
{
id: 2,
name: "系统管理",
path: "/system",
icon: "el-icon-setting",
children: [
{ id: 21, name: "用户管理", path: "/system/user" }
]
}
]
递归组件实现多级菜单
使用递归组件处理无限层级菜单。创建 MenuItem.vue 组件:
<template>
<el-submenu v-if="item.children" :index="item.path">
<template #title>
<i :class="item.icon"></i>
<span>{{ item.name }}</span>
</template>
<menu-item
v-for="child in item.children"
:key="child.id"
:item="child"
/>
</el-submenu>
<el-menu-item v-else :index="item.path">
<i :class="item.icon"></i>
<span>{{ item.name }}</span>
</el-menu-item>
</template>
<script>
export default {
name: 'MenuItem',
props: {
item: Object
}
}
</script>
路由权限控制
结合 Vue Router 实现动态路由添加。在路由守卫中处理权限:
// router/index.js
router.beforeEach(async (to, from, next) => {
const hasMenu = store.getters.menuList.length > 0
if (!hasMenu) {
const menuData = await store.dispatch('getMenuData')
const routes = generateRoutes(menuData)
router.addRoutes(routes)
}
next()
})
// 动态路由生成函数
function generateRoutes(menuData) {
return menuData.map(item => ({
path: item.path,
component: () => import(`@/views${item.path}.vue`),
children: item.children ? generateRoutes(item.children) : []
}))
}
状态管理集成
使用 Vuex 集中管理菜单状态:
// store/modules/menu.js
export default {
state: {
menuList: []
},
mutations: {
SET_MENU(state, payload) {
state.menuList = payload
}
},
actions: {
async getMenuData({ commit }) {
const res = await api.getMenu()
commit('SET_MENU', res.data)
return res.data
}
}
}
响应式菜单激活
处理菜单激活状态与路由同步:
<!-- MainLayout.vue -->
<el-menu
:default-active="$route.path"
:router="true"
@select="handleSelect"
>
<menu-item
v-for="item in menuList"
:key="item.id"
:item="item"
/>
</el-menu>
菜单权限过滤
根据用户角色过滤可见菜单项:
// utils/auth.js
export function filterMenu(menuData, roles) {
return menuData.filter(item => {
if (item.meta?.roles) {
return item.meta.roles.some(role => roles.includes(role))
}
return true
}).map(item => {
if (item.children) {
item.children = filterMenu(item.children, roles)
}
return item
})
}
性能优化建议
对于大型菜单系统,可采用以下优化方案:
- 菜单数据懒加载:只在展开父菜单时加载子项
- 使用 keep-alive 缓存高频访问的菜单组件
- 对菜单数据进行扁平化处理,减少递归深度
典型问题解决方案
处理菜单图标动态加载:
// 创建图标映射
const iconMap = {
'home': 'el-icon-house',
'user': 'el-icon-user'
}
// 在组件中使用
<i :class="iconMap[item.iconKey]"></i>
处理外链菜单项:
<el-menu-item
v-if="item.isExternal"
@click="window.open(item.path)"
>
外链菜单
</el-menu-item>






