最近项目的权限管理用到了vue-router的addRoutes方法,这里记录一下
业务场景
1.用户登陆 — 获取权限 — 判断权限 — 生成动态路由
2.用户刷新,停留在原页面
3.用户退出 — 重新登陆 — 获取权限 — 判断权限 — 生成新的动态路由
遇到的坑
1.重新登陆生成动态路由时,vue-router提示 [vue-router] Duplicate named routes definition:*
2.跳转到生成的动态路由,然后点击刷新,发现路径是对的,但是页面却显示404
坑点1解决方法
第一个问题是因为当我们第一次登陆后就把生成的动态路由添加到router中,但是退出再登陆并没有清空添加的动态路由,官方只提供 addRoutes 方法,但是并没有提供清除路由的方法。路由重复了,所以就报错了。
解决方法:
- 首先在router/index.js 文件中写入下面的方法
// router/index.js
// 重置路由
router.$addRoutes = (params) => {
router.matcher = new VueRouter({ mode: 'history' }).matcher
router.addRoutes(params)
}
- 然后在添加动态路由的地方使用
router.$addRoutes([...routes, ...routeLists])
// routes 是基础路由
// routeLists 是动态生成的路由
坑点2解决方法
因为路由是放到状态管理里面的,所以浏览器一刷新,就会清空状态管理,没有了动态生成的路由,就会跳转到错误页。
解决方法:
- 监听路由的beforeEach,并利用vuex判断是否已经加载过权限了,如果没有加载过,就重新获取接口,并动态生成路由
// router/index.js
router.beforeEach(async (to, from, next) => {
if (!store.state.mod.permission.permissionLoaded) {
// console.log('未加载权限')
await store.dispatch('mod/permission/isLoaded')
}
next()
})
// permission.js
export default {
namespaced: true,
state: {
// 是否加载过权限
permissionLoaded: false,
// 权限路由信息
perRouteLists: []
},
actions: {
// 判断是否加载过路由信息
isLoaded ({ state, dispatch }) {
return new Promise(async resolve => {
if (state.permissionLoaded) {
resolve()
return
}
// 要先把permissionLoaded设置未true,否则可能会死循环
state.permissionLoaded = true
await dispatch('initRoutes')
resolve()
})
},
// 获取权限列表
initRoutes ({ state, commit, dispatch }) {
return new Promise((resolve, reject) => {
// 获取权限列表
return GetPermission().then(async res => {
if (res && res.code === 200) {
// formatRoutes方法用于格式化路由格式
let routeLists = formatRoutes(menus)
state.perRouteLists = routeLists
// 把路由放到全局
await router.$addRoutes([...routes, ...routeLists])
}
}).catch(err => {
reject(err)
})
})
}
},
mutations: {
}
}
- 万事俱备,赶紧刷新试一试,发现又gg。明明已经添加了动态路由,但是还是没用?在beforeEach方法中把 路由去向打印出来,发现name是 404,what?明明是在人员管理页啊,难道在还没生成动态路由前,想要跳转‘/user’,但是这个路由并不存在,所以就跳转到了错误页(猜测)?
- 接着在生成动态路由后使用 ==router.replace(to.path)==竟意外解决了,神奇!
// router/index.js
router.beforeEach(async (to, from, next) => {
if (!store.state.mod.permission.permissionLoaded) {
// console.log('未加载权限')
await store.dispatch('mod/permission/isLoaded')
router.replace(to.path)
}
next()
})