vue实现的菜单管理
Vue 实现菜单管理的核心方案
数据结构设计
菜单数据通常采用树形结构存储,包含以下字段:
{
id: Number,
name: String,
path: String,
icon: String,
children: Array
}
递归组件实现
创建MenuComponent.vue递归组件:
<template>
<div v-for="item in menuData" :key="item.id">
<router-link v-if="!item.children" :to="item.path">
<i :class="item.icon"></i>
<span>{{ item.name }}</span>
</router-link>
<div v-else>
<div @click="toggleSubMenu(item)">
<i :class="item.icon"></i>
<span>{{ item.name }}</span>
</div>
<MenuComponent
v-show="item.expanded"
:menu-data="item.children"
/>
</div>
</div>
</template>
<script>
export default {
name: 'MenuComponent',
props: ['menuData'],
methods: {
toggleSubMenu(item) {
this.$set(item, 'expanded', !item.expanded)
}
}
}
</script>
状态管理方案
使用Vuex存储菜单状态:
// store/modules/menu.js
const state = {
menuItems: [],
activeMenu: null
}
const mutations = {
SET_MENUS(state, menus) {
state.menuItems = menus
},
SET_ACTIVE_MENU(state, menu) {
state.activeMenu = menu
}
}
const actions = {
async fetchMenus({ commit }) {
const res = await api.getMenus()
commit('SET_MENUS', res.data)
}
}
动态路由集成
结合vue-router实现权限控制:
// 路由配置示例
const routes = [
{
path: '/dashboard',
component: Dashboard,
meta: { menuId: 1 }
},
// 其他路由...
]
// 路由守卫中校验菜单权限
router.beforeEach((to, from, next) => {
const hasPermission = store.getters.menus.some(
menu => menu.id === to.meta.menuId
)
hasPermission ? next() : next('/403')
})
可视化菜单编辑器
实现拖拽排序功能:
<template>
<draggable
v-model="menuTree"
group="menus"
@end="saveMenuOrder"
>
<div v-for="item in menuTree" :key="item.id">
{{ item.name }}
<menu-editor v-if="item.children" :menu-tree="item.children"/>
</div>
</draggable>
</template>
<script>
import draggable from 'vuedraggable'
export default {
components: { draggable },
props: ['menuTree'],
methods: {
async saveMenuOrder() {
await api.updateMenuOrder(this.menuTree)
}
}
}
</script>
性能优化建议
- 使用
v-if替代v-show处理深层级菜单 - 对静态菜单数据使用
Object.freeze - 实现虚拟滚动处理超长菜单列表
- 添加菜单缓存机制减少重复请求
典型问题解决方案
菜单激活状态保持
watch: {
'$route'() {
this.$store.commit('SET_ACTIVE_MENU', this.findActiveMenu())
}
},
methods: {
findActiveMenu() {
// 根据当前路由匹配菜单项
}
}
多级菜单缩进处理
.menu-item {
padding-left: 20px;
&.level-2 {
padding-left: 40px;
}
/* 更多层级... */
}






