动态路由中涉及到页面操作权限时的addRoute路由更新无效问题
场景
- 网站根据用户等级有操作权限的限制,不光是菜单列表不同,页面按钮的操作权限也不同,这肯定就需要和后台配合使用动态路由管理页面权限。而页面按钮的权限也需要在解析后台返回的json字段中带的权限字段来控制,所以也要放到router里,在页面访问时,通过$route获取当前页面的操作权限等级
问题
- 现在遇到的问题是,首次登录或者刷新页面时,路由的解析都是正确的,没有任何问题,但是如果没有刷新页面,而是退出登录,切换了另一个权限级别的账户,登录之后的路由解析出来的是上一轮账户的权限等级。刷新之后又对了,现在如何不刷新,就能正确的切换用户权限级别?
解决
- 先看路由解析,存页面权限,动态路由处理以前有分析过,跳转
其实很简单,做好了路由解析,在路由对象的meta里存权限字段就行了,存其他地方好像通过$route拿不到,具体什么原因暂时没有深究。const currentRouter = { ... // meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉) meta: { title: item.title, icon: item.icon || undefined, hiddenHeaderContent: item.hiddenHeaderContent, target: item.target, permission: item.name, // 如果是个页面,保留它的权限字段 jurisdiction: item.jurisdiction || undefined } }
- 然后是当前页面访问自己的页面权限,activated用于对被
包裹的组件监听其活跃状态,每次重新访问页面时触发,这里我们用 包裹整个路由页面的 ,就能对所有页面监听activated activated () { // 访问当前页面权限字段,权限解析自行处理 console.log(this.$route.meta.jurisdiction) }
- vue2中可封装成mixin,vue3中可封装成derocator
- 以上都是基本思路,这样走下来,就会遇到笔者开始提到的问题了。切换另一个权限级别的用户时,路由里的权限等级没有更新。
- 分析:
既然刷新没问题,只是在重登的时候出了问题,那问题就应该是出在重登时的路由解析。
这段代码是哪儿出了问题呢?
经过排查,每次重登处理的addRouters都是正确的,带的权限字段是对的,但是在addRoute之后的router却有问题,输出的路由表只有新增,没有清除第二次处理时没有的路由。那么就基本可以确认,是addRoute这里出了问题,它没有一个清空操作,所以导致多次处理之后的结果是路由累积。if (store.getters.addRouters.length === 0) { // 表示还没生成新路由 store.dispatch('GenerateRoutes', { roles }).then(() => { // 重登后的addRouters是更新了的 const addRouters = store.getters.addRouters for (let i = 0; i < addRouters.length; i++) { router.addRoute(addRouters[i]) } console.log(router.getRoutes()) // 查看更新后的router的路由表 const redirect = decodeURIComponent(from.query.redirect || to.path) if (to.path === redirect) { next({ ...to, replace: true, query: to.query }) } else { next({ path: redirect, query: to.query }) } }) } else { next() }
- 解决思路
既然是没有清空,那可不可以重新声明一个Router,然后再addRoute呢?
下面的代码,我们再addRoute之前,先重声明一个Router,并将它的matcher给到原router,这样router的路由匹配就是走的新的Router,但是,重点,一开始忽略了一个东西,导致出了点问题,卡了很久。重点是重新声明的Router不要忘记配一下静态路由,比如登录页,404页这些都是放在静态路由里的,不是通过后台返回的json解析的,如果忘了它们,就会少几个页面了。
所以这里routes: constantRouterMap
就是引入静态路由if (store.getters.addRouters.length === 0) { // 表示还没生成新路由 store.dispatch('GenerateRoutes', { roles }).then(() => { // 重登后的addRouters是更新了的 const addRouters = store.getters.addRouters router.matcher = new Router({ mode: 'hash', // routes: constantRouterMap, // 引入的公共路由 base: process.env.BASE_URL }).matcher // reset router for (let i = 0; i < addRouters.length; i++) { router.addRoute(addRouters[i]) } const redirect = decodeURIComponent(from.query.redirect || to.path) if (to.path === redirect) { next({ ...to, replace: true, query: to.query }) } else { next({ path: redirect, query: to.query }) } }) } else { next() }
- 分析: