开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情
前言
在前文中使用自定义指令完成了对功能按钮权限的控制,今天记录一下如何利用addRoute来控制页面权限
addRoute
addRoute: 添加一条新的路由记录到路由。如果路由有一个 name,并且已经有一个与之名字相同的路由,它会先删除之前的路由。
addRoute(route: RouteRecordRaw): () => void
页面权限
登录的用户不同,用户的权限不同,有些页面则无需显示,利用addRoute API,可以将用户拥有的权限页面增加进路由,无权限的不需要添加。登录用户不同,也能动态的显示用户已有的权限页面
在router/index.js,创建两个变量privateRoutes和publicRoutes,私有路由表保存需要权限的路由,公共路由表保存不需要权限的路由
// 私有路由表
export const privateRoutes = []
// 公有路由表
export var publicRoutes = []
const router = createRouter({
history: createWebHashHistory(),
routes: publicRoutes
})
接着需要一个模块单独处理路由,在vuex中新建一个控制路由权限的模块,其中routes是初始路由表,初始只有不需要权限的页面的路由,setRoutes设置新的路由表,filterRoutes的作用是根据权限筛选路由
store/modules/permission.js
// 处理权限路由的模块
import { publicRoutes, privateRoutes } from '@/router'
export default {
namespaced: true,
state: {
// 路由表:初始拥有静态路由权限
routes: publicRoutes
},
mutations: {
setRoutes(state, newRoutes) {
// 永远在静态路由的基础上增加新路由
state.routes = [...publicRoutes, ...newRoutes]
}
},
actions: {
/**
* 根据权限筛选路由
*/
filterRoutes(context, menus) {
}
}
}
接下来补充privateRoutes,我们将所有权限路由加入到私有路由表中
举个栗子,以下是一个权限路由,这里注意路由要加上name属性,我们依靠name属性值去判断用户是否含有该页面权限,在用户登录后,获取的个人信息中保存有menus数组,其中包含用户拥有的页面权限,menus数组中的内容和路由中的name值是相对的
import layout from '@/layout'
export default {
path: '/user',
component: layout,
redirect: '/user/manage',
name: 'userManage',
meta: {
title: 'user',
icon: 'personnel'
},
children: [
{
path: '/user/manage',
component: () => import('@/views/user-manage/index'),
meta: {
title: 'userManage',
icon: 'personnel-manage'
}
},
{
path: '/user/info/:id',
name: 'userInfo',
component: () => import('@/views/user-info/index'),
props: true,
meta: {
title: 'userInfo'
}
},
{
path: '/user/import',
name: 'import',
component: () => import('@/views/import/index'),
meta: {
title: 'excelImport'
}
}
]
}
将其加入私有路由表
···
import UserManageRouter from './modules/UserManage'
···
export const asyncRoutes = [
···
UserManageRouter,
···
]
将权限路由全都加入私有路由表完成之后,接下来去完善vuex permission.js模块中的filterRoutes方法,该方法需要传入用户的menus数组,即用户所拥有的权限页面的name值,根据name值,从私有路由表中筛选出含有每个name的路由,返回一个数组,这个数组保存的就是用户拥有的权限路由
import { publicRoutes, privateRoutes } from '@/router'
filterRoutes(context, menus) {
// 筛选后需要通过addRoute进行添加的路由表数组
const routes = []
menus.forEach((key) => {
routes.push(...privateRoutes.filter((item) => item.name === key))
})
// 所有不匹配的路由都进入404
// 必须写在最后
routes.push({
path: '/:catchAll(.*)',
redirect: '/404'
})
context.commit('setRoutes', routes)
return routes
}
接着在路由导航守卫中调用该函数获取用户拥有的权限路由,通过addRoute方法加入router
router.beforeEach(async (to, from, next) => {
// 用户已登录 不进login
// 用户未登录 只进login
if (store.getters.token) {
if (to.path === '/login') {
next('/')
} else {
if (!store.getters.hashUserInfo) {
// 这里是获取用户的权限数组
const { permission } = await store.dispatch('user/getUserInfo')
// 获取用户权限路由
const filterRoutes = await store.dispatch(
'permission/filterRoutes',
permission.menus
)
// 利用 addRoute 循环添加
filterRoutes.forEach((item) => {
router.addRoute(item)
})
// store.dispatch('user/getUserInfo')
// 添加完动态路由之后,需要在进行一次主动跳转
return next(to.path)
}
next()
}
}else {
···
}
至此页面权限控制已经完成,但是当我们退出登陆时,添加的路由表没有删除,当另一个用户登录时,菜单是没有变的,只有手动刷新,才能展示最新的路由表,所以当用户退出时,需要将动态添加的路由删除
这里需要用的removeRoute API: 通过名称删除现有路由。
在router/index.js导出方法,它的作用是将动态添加的路由删除
export function resetRouter() {
if (
store.getters.userInfo &&
store.getters.userInfo.permission &&
store.getters.userInfo.permission.menus
) {
// 获取用户权限数组
const menus = store.getters.userInfo.permission.menus
menus.forEach((menu) => {
router.removeRoute(menu)
})
}
在退出时调用该方法即可
import { resetRouter } from '@/router'
logout() {
resetRouter()
...
}