加载动态路由

# 寻找路由配置

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}`);
}
1
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();
    }
  }
});
1
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);
},
1
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;
},
1
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
上次更新: 2024/11/10, 11:19:17
最近更新
01
docker-compose笔记
01-12
02
MySQL数据迁移
11-27
03
Docker部署服务,避免PID=1
11-27
更多文章>