vue如何配置动态路由

17,512 阅读5分钟

简述

在工作之前我一直想亲手从零搭建一个PC系统后台模板,然后由于自己工作和懒的缘故(emmm其实就是懒) 一直没有搭建成功,这次疫情也让我拥有了充分的时间更深层次的去了解搭建一个完整的PC后台的效果,想把这次成果记录下来。

脚手架地址


功能如下

- 登录 / 注销

- 权限验证
  - 页面权限
  - 指令权限
  - 权限配置
  - 动态路由配置
  • 其实这部分我直接抄录的vue-admin那个github上很成熟的库,但是说实话虽然我知道有这个库,我也没用过,这次是一次全新的尝试,也是加深自己对vue全家桶最好的总结,

记录的缘由

  • 在细谈PC后台系统时,有两点我觉得尤为重要,第一,动态配置路由,二是按需加载文件。公司的项目之前我来维护,我深深感觉到一个按需加载对系统后台的重要性,项目过大时,打包十分耗时

动态配置路由

路由目录结构的讲究

  1. 动态配置路由的第一步就是将异步路由与同步路由区分开来,首先在目录上就要分出胜负
- router
    - asyncRoutes.js
    - commonRoutes.js
    - index.js 总入口
    
//目录详参
import Lyout from './Lyout' //基础布局组件包括header aside main
const asyncRoutes[{
    path:'/auth',
    name:'auth'
    meta:{
        ismenu:true, //为了filter出所有为侧边栏目录的路由
        roles:['admin','user']
    },
    component:Lyout,
    children:[{
        //以下省略,权限同上,通过字段控制
    }]
}]

在commonRoutes中我们更多的是放入login,404等无需加载的公共页面,此时这些页面直接注入到Router实例,并无其他特别,配置好之后我们默认进入login页面

import routes from './modules/commonRoutes'
const roter=()=>new Router({
    routers
})
//init时只需要commonRoutes

登录页面vuex的使用

  1. 在当下使用vuex进行数据操作已经非常普遍,登录之后直接将将后台返回的role, 进行前端判断,生成权限路由分配给router
// store.js
function filterRoutes(filterRoutes, role) {
  let res = [];
  filterRoutes.forEach(route => {
    const roles = route.meta.roles;
    roles.includes(role) ? res.push(route) : ''
  })
  return res
}
mutations: {
    addUser(state, userInfo) {
      const accessRoutes = filterRoutes(asyncRoutes, userInfo.role);
      resetRouter()
      router.addRoutes(accessRoutes)
      state.routes = accessRoutes
    }
  }


此时需要注意的是vue-router中的addRoutes有一个坑,此函数仅仅只能添加,而不会覆盖或者重置,如果不处理这种情况,你会无限出现 Duplicate named routes definition 如下图,直至你的程序凉凉

关于Duplicate named routes definition

首先这个问题的出现是由于路由重复出现,然后在真实的场景中 哪怕你打印console.log(this.$router.options.routes)发现自己的路由也是没有问题的,这个问题出现我分为两种

因为path的name属性重复

以下这种情况大多数人可能一眼就看出来了,是一个不经常犯的例子

{
    path:'/a',
    name:'name'
},
{
    path:'/b',
    name:'name'
}

注入路由,清除路由的地点不对

  1. 首先这种问题的解决方案就是如下代码,当然你可以在router实例上挂载一个新的addRoutes在这之前使用matcher清除, 但是不太建议挂,直接清除就好
export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}

接下来具体讲讲要在哪里注入路由和清除路由

  1. :在登录时注入

由于addRoutes官网介绍十分简短,获取到role后直接注入会导致一个问题,如果用户返回,或者退出,这个时候vue实例还是保留原有的状态,那么你会在之前已经有a,b路由的同时,登录之后再注入一次a,b路由。就会出现Duplicate named routes definition

解决办法:所以需要在每次鉴权添加路由之前,都要清除之前asyncROutes的痕迹 ,也就是调用我们的resetRouter

  1. 在注入vue实例之前,注入peimission.js 鉴权逻辑

解决方法: 因为在页面跳转时,main.js会执行一遍,那么在注入页面之前做404判断,鉴权操作都是十分合适的,同理,也应该清除路由痕迹,然后借由role或者token 去获取当前用的路由,此处强烈建议使用asynv await等语法糖 配合vuex 十分之香

  • 注入路由
  1. 在login之后

此问题的原因就是你的路由重复了,如果真是重复了,那把name改一改也就成,细心的朋友一般不会出现这种问题,但是以下场景如不提前优化则也会出问题,比如当用户退出登录时,用户点击左上角的返回又进入到login页面时

解决方案

  1. 无论是用户登录,修改用户权限等等涉及用户权限路由判断的情况,都应先清除之前addRoutes的路由,已保证不重复,不冲突
export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}
//说句实在话。。野文档有很多是在router实例上直接新增一个方法,然而并不可靠,这里我也是唯一一个借鉴了vue-admin的地方

//重回addUser函数

结语

其实还有更多的功能想自己亲自实现,但是我认为PC系统后台最关键的点就是权限的控制,按需加载的量大功能点,其余的功能点更多是不同项目的特色服务,更像是锦上添花的功能