基于Vue3+ElementPlus+Router+Store实现动态菜单(支持1-3级),应用于后台管理系统中,根据管理员的权限值自动生成相应的菜单进行展示,是每个管理后台系统最基础的功能,适用于大部分后台管理系统
Router路由
{
path: '/home',
component: () => import('../views/Home.vue'),
redirect: '/home/dataShow',
children: [
/**
* 说明:
* menuLevel 为导航级别,按顺序写
*/
{
path: 'dataShow',
name: '数据概况',
menuLevel: 1,
adminTypes: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
component: () => import('../components/DataShow.vue'),
icon: 'histogram',
},
{
path: 'system',
name: '系统管理',
menuLevel: 1,
icon: 'cpu',
},
{
path: 'system/adminUser',
name: '管理员管理',
menuLevel: 2,
component: () => import('../components/system/AminUser.vue'),
},
{
path: 'update',
name: '更新管理',
menuLevel: 2,
},
{
path: 'system/appUpdate',
name: 'APP更新管理',
menuLevel: 3,
component: () => import('../components/system/AppUpdate.vue'),
},
{
path: 'system/PCUpdate',
name: 'PC更新管理',
menuLevel: 3,
component: () => import('../components/system/PCUpdate.vue'),
},
// --------------------------分------割-------------------------------
{
path: 'system/breakRouter',
menuLevel: 4,
},
...other
]
},
菜单组件
<!--菜单-->
<template>
<div class="home-menu">
<el-menu
:default-active="store.state.menuIndex"
router
background-color="#304156"
text-color="#ddd"
active-text-color="#409eff"
:collapse="store.state.menuCollapse">
<menuTree :menuList="store.state.menuTree"></menuTree>
</el-menu>
</div>
</template>
<script setup>
import store from '../../store'
import router from '../../router'
import menuTree from './MenuTree.vue'
menu()
// 菜单计算(将路由转为为菜单树)
function menu() {
// 获取所有菜单列表
let menus = router.options.routes[0].children
let oneItem = {}
let twoItem = {}
let oneMenu = []
let twoMenu = []
let threeMenu = []
for (let item of menus) {
// 分割
if (item.menuLevel === 4) {
break
}
item.path = '/home/' + item.path
if (item.menuLevel === 1) {
if (threeMenu.length > 0) {
twoItem.ch = threeMenu
twoMenu.push(twoItem)
twoItem = {}
threeMenu = []
}
if (twoMenu.length > 0) {
oneItem.ch = twoMenu
oneMenu.push(oneItem)
oneItem = {}
twoMenu = []
}
if (item.component) {
// 该级别可点击,校验是否有权限
menuShowRule(item, () => {
// 没有下级,直接添加进最后数据
oneMenu.push(item)
})
} else {
// 不可点击
oneItem = item
}
} else if (item.menuLevel === 2) {
if (threeMenu.length > 0) {
twoItem.ch = threeMenu
twoMenu.push(twoItem)
twoItem = {}
threeMenu = []
}
if (item.component) {
// 该级别可点击,校验是否有权限
menuShowRule(item, () => {
// 没有下级,直接添加进数据
twoMenu.push(item)
})
} else {
// 不可点击
twoItem = item
}
twoItem = item
} else if (item.menuLevel === 3) {
menuShowRule(item, () => {
threeMenu.push(item)
})
}
}
if (threeMenu.length > 0) {
twoItem.ch = threeMenu
twoMenu.push(twoItem)
}
if (twoMenu.length > 0) {
oneItem.ch = twoMenu
oneMenu.push(oneItem)
}
// 保存菜单
store.commit('setMenuTree', oneMenu)
}
/**
* 定义是否显示的规则
*/
function menuShowRule(item, fun) {
// 自己部门的权限
if (item.adminTypes.includes(store.state.adminType)) {
fun()
}
}
</script>
<style scoped lang="sass">
// 菜单高度
.el-menu-item
height: 45px
.el-sub-menu
height: 45px
// 去除菜单边框
.el-menu
border-right: none
</style>
递归显示组件
<template>
<template v-for="menu in menuList">
<!--没有子菜单-->
<el-menu-item v-if="menu.component" :index="menu.path" @click="store.commit('setMenuIndex', menu.path)">
<el-icon>
<component :is="menu.icon"></component>
</el-icon>
<span>{{ menu.name }}</span>
</el-menu-item>
<!--有子菜单-->
<el-sub-menu
v-else
:index="menu.path">
<template #title>
<el-icon>
<component :is="menu.icon"></component>
</el-icon>
<span>{{ menu.name }}</span>
</template>
<!--递归调用自身-->
<MenuTree :menuList="menu.ch"></MenuTree>
</el-sub-menu>
</template>
</template>
<script setup>
import store from '../../store'
defineProps({
menuList: {
type: Array,
required: false,
}
})
</script>
<style scoped>
</style>