动态路由

动态路由通俗点来讲就是,同一个系统,每个人登录上去,所看到的页面菜单是不同的,根据每个人的权限去分配页面。

后台的设计思想

后台的话会有以下几个表单:

用户表(所有用户的信息);
角色表(超级管理员,管理员,总裁…);
关系表(记录哪个角色拥有哪个权限);
权限表(也就是菜单表);
每一个用户都会给他分配一个角色,这个角色能不能去查看这个菜单

前端实现

一般使用方法三的情况比较多

方法一

把所有对应菜单的路由都写进去,把所有的路由写死
弊端:当用户通过url进入的时候,页面也会取显示

方法二

不同的角色注册不同的路由
例如:

superadimin:[{},{},{}]
admin:[{},{}],
user:[{}]…
登录->userInfo->role.name(角色)->动态的加载数组[]->main.routers

弊端:
新增角色时,需要修改前端代码,重新进行部署

方法三

根据菜单动态的生成路由映射

菜单->url->路由->path->component
例:角色管理->路径/mian/role->path->component
此时的component一个数组routes,添加到main childern里面

此时的动态生成也有两种方案:

  1. 菜单中就有加载组件的名称
    1.1 返回就有component:Role.vue(此时前后端名称/路径必须保持一致)
  2. 菜单中只有url
    2.1 前端代码中有各自的映射关系:path1->component1;path2->component2…

具体代码实现

可以写在router里面,但是此时这个项目建议写在store里面

store部分总共分为两部分:

  • 用户的菜单映射到路由上面
  • 将routes添加到router.main.children

由于映射的代码比较复杂,所以在unils/map-menus.ts文件进行写相关逻辑

import { RouteRecordRaw } from 'vue-router'

export function mapMenusToRoutes(userMenus: any[]): RouteRecordRaw[] {
  const routes: RouteRecordRaw[] = []

  // 1.先去加载默认所有的routes
  const allRoutes: RouteRecordRaw[] = []
  //require.context('../router/main')webpack的函数,true是否进行递归:如果main文件夹下面还有文件夹就是写为true;如果main下面没有文件夹的情况下false,第三个参数正则表达式:匹配我们找到的文件
  //在../router/main路径下去匹配.ts后缀的文件
  const routesFiles = require.context('../router/main', true, /\.ts/)
  //routesFiles.keys()拿到的式所有的文件的路由,是webpack特殊的函数,固定的写法
  routesFiles.keys().forEach((key) => {
    //通过.进行切割,拿到.后面的路径
    const route = require('../router/main' + key.split('.')[1])
    allRoutes.push(route.default)
  })

  // 2.根据菜单获取需要添加的routes
  //通过递归函数进行对菜单的获取
  // type === 1 -> children-> type===1
  //type === 2 -> url -> route
  const _recurseGetRoute = (menus: any[]) => {
    for (const menu of menus) {
      //需要映射的路由
      if (menu.type === 2) {
        // find只会找到一个,filter只要符合条件可以找到很多个
        const route = allRoutes.find((route) => route.path === menu.url)
        if (route) routes.push(route)
      } else {
        _recurseGetRoute(menu.children)
      }
    }
  }
  _recurseGetRoute(userMenus)

  return routes
}

store中相关的代码:

// userMenus=>routes,由于映射比较复杂,所以写在了utils/map-menus.ts文件里面
      const routes = mapMenusToRoutes(userMenus)
      console.log(routes)

      //将routes添加到router.main.children
      routes.forEach((route) => {
        router.addRoute('main', route)
      })

添加相关的点击事件

const handleItemClick = (item: any) => {
      console.log(item.url)
      router.push({
        path: item.url ?? '/not-found'
      })
    }
Logo

前往低代码交流专区

更多推荐