// @/utils/permission /** * 创建有权限的路由配置(多级) * @param {Object} config - 路由配置对象 * @param {Object} config.redirect - 必须是 children 中的一个,并且使用 name */ function createPermissionRouter ({ redirect, children = [], ...others }) { const needRecursion = !!children.length if (needRecursion) { return { ...others, redirect: createRedirectFn(redirect, children), children: children.map(item => createPermissionRouter(item)) } } else { return { ...others, redirect } } }
这样我们只需要在最外层的 router 配置加上这样一层函数就可以了:
import { createPermissionRouter } from '@/utils/permission' const routesConfig = [ { path: '/user', name: 'User', label: '用户', meta: { permissions: ['U_1'] }, redirect: { name: 'UserList' }, children: [ { path: 'list', name: 'UserList', label: '用户列表', meta: { permissions: ['U_1_1'] } }, { path: 'group', name: 'UserGroup', label: '用户组', meta: { permissions: ['U_1_2'] }, redirect: { name: 'UserGroupList' }, children: [ { path: 'list', name: 'UserGroupList', label: '用户组列表', meta: { permissions: ['U_1_2_1'] } }, { path: 'config', name: 'UserGroupConfig', label: '用户组设置', meta: { permissions: ['U_1_2_2'] } } ] } ] } ] export const routes = routesConfig.map(item => createPermissionRouter(item)) const router = new VueRouter({ routes }) export default router
当然这样写还有一个好处,其实你并不需要设置 redirect,这样会自动重定向到 children 的第一个有权限的路由
侧边栏显示问题
我们的项目使用的是根据路由的配置来生成侧边栏的,当然会加一些其他的参数来显示显示层级等问题,这里就不写具体代码了,如何解决侧边栏 children 全都无权限不显示的问题呢。
这里我的思路是,把路由的配置也一同更新到 vuex 中,然后侧边栏配置从 vuex 中的配置来读取。
由于这个地方涉及修改的东西有点多,而且涉及业务,我就不把代码拿出来了,你可以自行实验。
方便团队部署权限点的方法
以上我们解决了大部分权限的问题,那么还有很多涉及到业务逻辑的权限点的部署,所以为了团队中其他人可以优雅简单的部署权限点到各个页面中,我在项目中提供了以下几种方式来部署权限:
通过指令 v-permission 来直接在 template 上设置
<div v-permission="['U_1']"></div>
通过全局方法 this.$permission 判断,因为有些权限并非在模版中的
{ hasPermission () { // 通过方法 $permission 判断是否拥有权限 return this.$permission(['U_1_1', 'U_1_2']) } }
这里要注意,为了 $permission 方法的返回值是可被监测的,判断时需要从 this.$store 中来判断,以下为实现代码:
// @/utils/permission /** * 判断是否拥有权限 * @param {Array<string|number>} permissions - 要判断的权限列表 * @param {Object} permissionList - 传入 store 中的权限列表以实现数据可监测 */ function includePermissionWithStore (permissions = [], permissionList = []) { if (!permissions.length) return true return !!permissions.find(permission => permissionList.includes(permission)) }
import { includePermissionWithStore } from '@/utils/permission' export default { install (Vue, options) { Vue.prototype.$permission = function (permissions) { const permissionList = this.$store.state.permissionList return includePermissionWithStore(permissions, permissionList) } } }
以下为指令的实现代码(为了不与 v-if 冲突,这里控制显示隐藏通过添加/移除 className 的方式):
// @/directive/permission import { includePermission } from '@/utils/permission' const permissionHandle = (el, binding) => { const permissions = binding.value if (!includePermission(permissions)) { el.classList.add('hide') } else { el.classList.remove('hide') } } export default { inserted: permissionHandle, update: permissionHandle }
总结
针对之前的问题,有以下的总结:
1、什么时候获取 permissionList,如何存储 permissionList
router.beforeEach 获取,存储在 vuex。
2、子路由全都没权限时不应该显示本身(例:当用户列表和用户设置都没有权限时,用户也不应该显示在侧边栏)
通过存储路由配置到 vuex 中,生成侧边栏设置,获取权限后修改 vuex 中的配置控制显示 & 隐藏。