最近在写后台管理系统时,发现老系统有个需求,就是动态加载菜单
以往的静态菜单:路由都放在router/config.js
中,菜单页面放在pages里面。
加载的动态菜单:路由是通过接口获取,然后加载到路由中,菜单页面一九放在pages里面。
下面记录一下通过chatGPT
获取到的加载动态菜单路由的步骤:
chatGPT免费使用链接:https://chat.wuguokai.cn/#/chat/1684457211121
前言
vue3-antd-admin
是一个基于vue3
和ant design vue
的后台管理系统模板,支持加载动态菜单,下面是加载动态菜单的步骤
1.通过接口获取菜单数据,并将数据存储到vuex
中
//store/modules/menu.js
import { getMenuList } from '@/api/menu';//调用获取菜单接口
const state = {
menuList:[],//存放菜单数据
}
const mutations = {
SET_MENU_LIST(state,menuList){
state.menuList = menuList;
}
}
const actions = {
async fetchMenuList({commit}){
const res = await getMenuList()
commit('SET_MENU_LIST',res.data)
}
}
export default{
namespaced:true,
state,
mutations,
actions,
}
2.在Router全局前置守卫中动态生成路由
// router/index.js
import { createRouter,createWebHistory } from 'vue-router'
import store from '@/store'
import NProgress from 'nprogress'//页面加载进度条插件
import 'nprogress/nprogress.css'
import { message } from 'ant-design-vue'
const whiteList = ['/login']
const router = createRouter({
history:createWebHistory(process.env.BASE_URL),
routes:[]
})
router.beforeEach(async (to,from,next)=>{
NProgress.start()
document.title = to.meta.title?`${to.meta.title} - Antd Admin`:`Antd Admin`
if(!store.getters['user/token']&&!whiteList.includes(to.path)){
next('/login')
}else if(to.path === '/login'){
next();
}else {
//判断是否已经获取到菜单数据
if(store.getters['menu/menuList'].length>0){
next();
}else {
try{
//动态获取菜单数据
await store.dispatch('menu/fetchMenuList')
//根据菜单动态生成路由
const menuList = store.getters['menu/menuList']
const accessRoutes = generateRoutes(menuList)
//将动态生成的路由加入到路由表中
router.addRoute(accessRoutes)
next({...to,replace:true})
}catch(error){
message.error(error||'菜单加载失败,重新登录试试')
next(`/login?redirect=${to.path}`)
}
}
}
})
function generateRoutes(routes){
const res = [];
for(const route of routes){
const tmp = {...route}
if(tmp.component){
if(tmp.component.indexOf('Layout')!==-1){
tmp.component = Layout;
}else{
tmp.component = loadView(tmp.component)
}
}
if(tmp.children){
tmp.children = generateRoutes(tmp.children)
}
res.push(tmp)
}
return res
}
export default router
在上面的代码中,我们通过判断是否已经获取到菜单数据来决定是否请求接口获取数据,然后根据菜单数据的动态生成路由并加入路由表中
3.读取菜单数据和路由表
//components/Sidebar/SidebarMenu.vue
<template>
<a-menu mode="inlinel" theme="dark" :inline-collapsed="collapsed" :selected-keys="[currentPath]"
v-on:openChange="onOpenChange">
<a-sub-menu v-for="menu in sideMenus" :key="menu.id" :title="menu.name" v-if="hasChildren(menu)">
<template #title>
<app-icon :text="menu.icon" />
<span>{{menu.name}}</span>
</template>
<sidebar-menu-item v-for="child in menu.children" :menu="child" :key="child.path"/>
</a-sub-menu>
</a-menu>
</template>
<script>
import { computed,defineComponent,ref } from 'vue'
import { useRouter } from 'vue-router'
import appRoutes from '@/router/routes'
export default defineComponent({
name:'SidebarMenu',
components:{
SidebarMenuItem,
},
setup(){
const router = useRouter();
const sideMenus = computed(()=>{
return appRoutes.filter(route=>!route.hidden)
})
const currentRoutePath = computed(()=>{
return router.currentRoute.value.path
})
const collapsed = ref(false)
function hasChildren(menu){
return menu.children&&menu.children.length>0
}
function onOpenChange(openKeys){
console.log(openKeys)
}
return {
sideMenus,
currentRoutePath,
collapsed,
hasChildren,
onOpenChange,
}
}
})
</script>
在上面代码中,我们先通过 computed
(计算属性)读取路由表和菜单数据,然后判断是否有子菜单,并在菜单中循环渲染,需要注意的是,在vue3
中,计算属性需要使用computed
创建。
这就是加载动态菜单的详细步骤。