router.addroutes 动态添加路由表实现权限控制
开发后台管理系统会涉及到根据用户权限来动态渲染侧边栏的问题,在vue2.2.0之后可以使用router.addroutes()来方便动态添加路由了。
addRoutes (routes: RouteConfig[]): void;
//动态添加更多的路由规则。参数必须是一个符合 routes 选项要求的数组。
先介绍下实现侧边栏动态渲染的大致方式:
在router.js
中配置静态路由表:
export const constantRouterMap = [{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},]
配置需要动态渲染的路由表:
export const asyncRouterMap = [{
path: '/admin',
component: () => import('@/views/admin/index'),
hidden: true,
meta: {
title: 'xxx',
icon: 'xxx',
//角色权限字段
role: ['admin']
}
},
{
...
//其他路由
}]
用户登录跳转时,导航守卫router.beforeEach()
发起ajax获取用户信息,拿到用户信息对应的role字段,再与asyncRouterMap[i].meta.role
进行比对,将比对结果作为条件滤出角色所属的路由表。
//permission.js
router.beforeEach(async (to, from, next) => {
// 验证用户是否已经登陆过
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
//是否跳转登录页
next({
path: '/'
})
} else {
//这一步为了路由数据持久化,防止刷新后vuex数据丢失造成的侧边栏显示异常
const hasGetRouters = store.getters.routers
//是否已经获取用户信息
const hasGetUserInfo = store.getters.name
if (hasGetUserInfo && hasGetRouters.length) {
next()
} else {
try {
//获取角色信息
const {
role
} = await store.dispatch('user/getInfo')
//传入角色信息,执行过滤方法
await store.dispatch('permission/getRoutes', {
role
})
//动态添加路由
router.addRoutes(store.getters.addRouters);
next({
...to,
replace: true
})
} catch (error) {
}
}
}
}
})
遇到的一些坑
已经成功拿到动态路由表,为什么使用router.addRoutes()
添加的路由没有在router.options
中更新?
作者有提到That is normal, options is the object passed to the vuerouter constructor. It's not modified afterwards
。链接在此,其实相应的路由已经添加了,只是将参数传给了vueRouter构造函数,所以没法在vueRouter实例中看到。
那么既然侧边栏不能通过v-for="route in $router.options"
渲染,如何才能实现有效更新?
如果使用router.addRoutes
来进行添加路由无法更新this.$router.options
,所以主要的实现方法是通过store来存储路由表。
//store
const state = {
routers: [],
addRouters: []
}
const mutations = {
SET_ROUTERS: (state, routers) => {
state.addRouters = routers;
//与静态路由表拼接
state.routers = constantRouterMap.concat(routers);
}
}
const actions = {
getRoutes({
commit
}, data) {
return new Promise(resolve => {
const {
role
} = data;
...
//过滤出role对应路由表accessedRouters
commit('SET_ROUTERS', accessedRouters);
resolve();
})
}
}
//sideBar.vue
...mapState("permission", {
routers: "routers",
}),
刷新之后侧边栏显示空白?
因为vuex无法持久化保存数据,在页面刷新之后数据被清空,所以需要在router.beforeEach()
内再做一层判断页面是否刷新。