因为项目中的需求菜单的生成由后端返回的个人信息进行配置,所以就使用了动态路由这个方法去实现项目菜单的动态加载,这一功能的完成主要涉及两个方面
一:动态路由的生成
这一部分我主要是在全局路由守卫中完成的,因为路由信息是后端返回的,所以使用async await,在获取菜单之后对路由对象进行封装,为了避免顶层使用await,我选择在路由全局守卫中进行对路由的封装和添加
router/index.js
import {createRouter, createWebHistory} from 'vue-router';
import routes from "./router";
import { useMainStore } from '../store';
import { commonApi } from '../API';
const router = createRouter({
history: createWebHistory(),
routes: routes
});
router.beforeEach(async(to, from, next) => {
const store = useMainStore()
if(to.fullPath!==""&&to.fullPath!=="/"){
//记录当前路由
store.selectedMenu = to.fullPath;
}
if(routes.length===1){
if(store.menuList.length===0){
//页面刷新时重新获取用户信息,保存菜单
await store.getUserInfo()
store.isRefreshMenu =true;
}
//封装动态路由对象
let route = {
path:"/",
name:'home',
redirect:store.menuList[0].menuUrl,
component:()=>import(/* @vite-ignore */"../views/main.vue"),
// component:defineAsyncComponent(()=>import(/* @vite-ignore */'../views/main')),
children:[]
}
//加载组件形成映射对象
let modules = import.meta.glob('../views/*/*.vue')
store.menuList.forEach((element,index1)=>{
route.children.push({
path:element.menuUrl,
name:element.menuName,
redirect:element.children[0].menuUrl,
// component:()=>import(/* @vite-ignore */`../views${element.menuUrl}/index.vue`),
component:modules["../views"+element.menuUrl+"/index.vue"],
// component:defineAsyncComponent(()=>import(/* @vite-ignore */`../views${element.menuUrl}/index`)),
children:[]
})
if(element.children.length>0){
route.children[index1].redirect = element.children[0].menuUrl;
route.children[index1].children=(element.children.reduce((value,item,index)=>{
value.push({
path:item.menuUrl,
// path:item.menuUrl,
name:item.menuUrl,
component:modules["../views"+item.menuUrl+".vue"],
// component:()=>import(/* @vite-ignore */`../views${item.menuUrl}.vue`),
// component:defineAsyncComponent(()=>import(/* @vite-ignore */`../views${item.menuUrl}`)),
meta:{
title:item.menuName,
icon:"el-icon-house"
}
})
return value;
},[]))
}
})
//添加动态路由
router.addRoute(route)
router.options.routes.push(route);
//重新执行路由守卫函数
next({...to,replace:true})
}else{
next();
}
});
export default router;
二:刷新之后路由和菜单的保持
我将菜单数组以及是否刷新的标识保存在store中了
main.js //菜单保持,下面逻辑大家根据自己项目进行更改
watchEffect(()=>{
//用户刷新页面时保存选择的菜单样式,且只刷新时执行一次
if(store.selectedMenu!==""&&store.isRefreshMenu){
const splitArray = store.selectedMenu.split("/");
const path = '/'+splitArray[1];
const childPath = path+"/"+splitArray[2];
if(routes[1].children.length>0){
const menuKey = routes[1].children.findIndex((element)=>{
return element.path === path;
})
selectedMenu.value = [menuKey]
if(routes[1].children[menuKey].children.length>0){
const childMenuKey = routes[1].children[menuKey].children.findIndex((element)=>{
return element.path === childPath;
})
nextTick(()=>{
leftMenuList.value = routes[1].children[menuKey].children;
})
selectedLeftKeys.value = [childMenuKey]
}
}
store.isRefreshMenu = false;
}
})
大家根据自己的router/route.js文件的内容以及自己项目中菜单的逻辑进行灵活变化。这里只是提供动态路由设置的核心代码以及相关核心思路。