动态注册路由 | 青训营笔记

171 阅读2分钟

这是我参与「 第五届青训营 」伴学笔记创作活动的第 15 天

动态注册路由

一、全局注册路由的弊端

1、在类似于后台管理系统的项目中,会出现许多不同等级的角色,其中系统菜单的开放权限对每个角色来说是有差异的,比如管理员可以获取所有菜单权限,用户只能获取部分菜单权限

2、如果管理员先登录了,通过接口获取到了菜单,那么对应的路由也会被注册,此时如果再切换到用户的帐号,虽然菜单上不会出现管理员的菜单,但是因为管理员的菜单路由被全局注册了,所以当手动输入url的时候,是可以跳转到对应路由的,这就是路由全局注册的弊端

二、动态注册路由

1、为了解决以上的问题,可以通过动态路由来代替全局路由去配置路由

2、使用动态路由也有两种方式,第一种是基于角色的动态路由管理,这样根据不用的角色定义路由,也有一定的弊端,那就是每增加一个角色,都要重新发布一个新版本

const roles = {
  "superadmin": [所有路由] => router.main.children,
  "admin": [一部分路由] => router.main.children,
	"service": [少部分路由] => router.main.children
}

3、第二种方法是基于菜单的动态路由管理,先获取userMenus动态展示菜单,再映射成路由对象,此时要求登录接口中请求三个内容:token、用户信息、菜单信息

4、具体的实现步骤:

  • 根据菜单动态添加路由对象(将路由放在独立的文件中)

    // router/main/... .ts
    export default {
      path: '/main/...',
      component: () => import('...')
    }
    
  • 动态获取所有路由对象(放在数组中)

    function loadLocalRoutes() {
      const localRoutes: RouteRecordRaw[] = []
      // 读取router/main中的所有ts文件
      const files: Record<string, any> = import.meta.glob(
        '../../router/main/**/*.ts',
        {
          eager: true
        }
      )
      for (const key in files) {
        const module = diles[key]
        localRoutes.push(module.default)
      }
      return localRoutes
    }
    
  • 根据菜单匹配正确路由

    export function mapMenusToRoutes(userMenus: any[]) {
      // 1.加载本地路由
      const localRoutes = loadLocalRoutes()
      // 2.根据菜单去匹配正确的路由
      const routes: RouteRecordRaw[] = []
      for (const menu of userMenus) {
        for (const submenu of menu.children) {
          const route = localRoutes.find((item) => item.path === submenu.url)
          if (route) routes.push(route)
        }
      }
      return routes
    }