前言
通常使用Vue2.x
开发后台管理系统会涉及到根据用户权限动态渲染侧边栏的需求。以前手动维护路由的方式比较繁杂,在Vue2.2
之后通过新增的router.addroutes
可以方便动态添加路由了。
Api
addRoutes (routes: RouteConfig[]): void;
//动态添加更多的路由规则。参数必须是一个符合 routes 选项要求的数组。
动态路由渲染过程
先介绍下实现侧边栏动态渲染的大致方式:
配置静态路由表:
// router.js
export const constantRouterMap = [{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},]
配置需要动态渲染的路由表:
// router.js
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存储路由表,但刷新之后侧边栏显示空白?
因为Vuex
无法持久化保存数据,在页面刷新之后数据被清空,所以需要在router.beforeEach()
内再做一层判断页面是否刷新,来判断是否进行持久化。