加载动态路由
# 寻找路由配置
在views/admin/login/index.vue
中,有如下代码:
if ( code == 200 ) {
await store.setToken(token);
proxy.$message.success({
content: '登陆成功',
duration: 2000,
});
setTimeout(() => {
proxy.$router.push('/admin/sys-api');
loading.value = false;
}, 500);
} else {
proxy.$message.error(`登陆失败:${msg}`);
}
2
3
4
5
6
7
8
9
10
11
12
13
当登录成功后,会跳转到/admin/sys-api
页面。
在router/index.js
中,并未发现/admin/sys-api
的路由,该文件中仅配置了根路径、登录页、403页面、500页面等少量的路由,其他路由应该是通过接口从后端获取动态加载到路由中。
类似检测未登录跳转到登录页,加载动态路由也是通过路由守卫实现的。
# 路由守卫检测路由
在router/index.js
中,有如下代码:
router.beforeEach(async (to, from, next) => {
const store = useUserStore();
const permissionStore = usePermissionStore();
// 获取系统配置信息
if (!store.sysConfig){
await store.getSysConfig();
}
if (!store.token && to.name !== 'login') {
next({ name: 'login' });
} else {
// 判断判断权限有无获取
if (store.token && !store.roles) {
await store.getUserInfo();
await permissionStore.getMenuRole();
permissionStore.addRouters.forEach((route) => {
router.addRoute('/', route);
});
// 如果 addRoute 并未完成,路由守卫会一层一层的执行执行,直到 addRoute 完成,找到对应的路由
next({ ...to, replace: true })
} else {
next();
}
}
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
当登录成功,要跳转路由到/admin/sys-api
时,会执行router.beforeEach
中的代码,这时token
已经存在,但是roles
不存在,会执行store.getUserInfo()
和permissionStore.getMenuRole()
,这两个方法会从后端获取用户信息和菜单权限信息,然后通过permissionStore.addRouters.forEach((route) => {router.addRoute('/', route);});
将动态路由添加到路由中。
# 加载后端路由数据
使用pinia
定义usePermissionStore
,用于存储路由和菜单权限信息。
在actions
中定义请求后端路由数据的方法:
async getMenuRole() {
const res = await getUserMenuRole();
this.setMenuList(res.data);
this.addRouters = await this.GenerateRoutes(res.data);
},
2
3
4
5
const modules = import.meta.glob('../views/**/*.vue');
加载views
目录下的所有.vue
文件,作为路由的component
对象。
import.meta.glob是Vite提供的一个特殊的全局方法,用于在构建时生成一个对象。这个对象的键是匹配到的文件路径,值是一个返回Promise的函数,用于动态导入对应的模块。通过这种方式,开发者可以实现按需加载(懒加载),即在需要某个组件时才动态导入该组件,而不是在应用启动时一次性加载所有组件。
将路由数据解析成路由格式:
GenerateRoutes(routeList) {
const routes = [];
routeList.forEach((item) => {
const route = {};
// if (item.visible == 0) {
if (item.menuType === 'M' || item.menuType === 'C') {
route.path = item.path;
route.name = item.menuName;
if (item.menuType === 'M') {
//菜单,路由到布局页面
route.component = modules[`../views/index.vue`];
} else if (item.menuType === 'C') {
//子路由,具体页面
route.component = modules[`../views${item.component}.vue`] || modules['../views/error-page/888.vue'];
}
route.meta = {
title: item.title,
permission: item.permission,
};
}
if (item.children) {
//递归解析子路由
route.children = this.GenerateRoutes(item.children);
}
routes.push(route);
});
return routes;
},
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30