vue2 角色权限
TomorrowLM 人气:0权限
路由权限
- 静态路由:固定的路由,没有权限。如login页面
- 动态路由:根据不同的角色,后端返回不同的路由接口。通过meta中的roles去做筛选
store存储路由
//地址:store/modules/permission import { routes as constantRoutes } from '@/router' // 根据meta.roles去判断该角色是否有路由权限 function hasPermission(roles, route) { if (route.meta && route.meta.roles) { return route.meta.roles.some(val => val === roles) } return true } /** * 递归动态路由 * @param routes 动态路由 * @param roles 角色 */ export function filterAsyncRoutes(routes, roles) { const res = [] routes.forEach(route => { const tmp = { ...route } if (hasPermission(roles, tmp)) { if (tmp.children) { //后台传来的路由字符串,转换为组件对象 // let a = `../views/${route.component}`; // route.component = () => import(a); // 导入组件 tmp.children = filterAsyncRoutes(tmp.children, roles) } res.push(tmp) } }) return res } //模拟后端传过来的路由 export const asyncRoutes = [ { path: '/', name: 'home', redirect: '/PickupTask', meta: { title: '首页', //纯前端去做动态路由 roles: ['admin'] }, component: () => import('@/views/HomeView.vue'), children: [ { path: 'PickupTask', name: 'PickupTask', meta: { title: 'PickupTask', }, component: () => import('@/views/Sd/PickupTask.vue'), }, { path: 'access', hidden: true, component: () => import('@/views/demo/Access.vue'), meta: { title: 'access', roles: ['admin'], //按钮权限标识 button: { 'btn:access:createUser': 'hidden', 'btn:access:editUser': 'disable' }, }, }, ], } ] const permisssion = { // namespaced: true, -> store.dispatch('permisssion/generateRoutes', 'admin'); state: { //静态路由+动态路由 routes: [], //动态路由 addRoutes: [] }, mutations: { SET_ROUTES: (state, routes) => { state.addRoutes = routes state.routes = constantRoutes.concat(routes) } }, actions: { generateRoutes({ commit }, roles) { return new Promise(resolve => { let accessedRoutes = filterAsyncRoutes(asyncRoutes, roles) commit('SET_ROUTES', accessedRoutes) resolve(accessedRoutes) }) } } } export default permisssion
router添加路由
将store中的动态路由使用addRoute添加(最新版本去掉了addRoutes只能使用addRoute添加路由)。
//地址:router/index import Vue from 'vue'; import VueRouter, { RouteConfig } from 'vue-router'; import store from '@/store'; Vue.use(VueRouter); const isProd = process.env.NODE_ENV === 'production'; const routerContext = require.context('./', true, /index.js$/); //静态路由 export let routes: any = []; routerContext.keys().forEach((route) => { // route就是路径 // 如果是根目录的index不做处理 if (route.startsWith('./index')) { return; } const routerModule = routerContext(route); routes = [...routes, ...(routerModule.default || routerModule)]; }); // 创建 router 实例,然后传 `routes` 配置 const router = new VueRouter({ mode: 'history', base: isProd ? '/vue-demo/' : process.env.BASE_URL, routes, scrollBehavior(to, from, savedPosition) { if (to.hash) { return { selector: to.hash, }; } }, }); let registerRouteFresh = true; /** * 全局全局前置守卫 * to : 将要进入的目标路由对象 * from : 即将离开的目标路由对象 */ router.beforeEach(async (to: any, from, next) => { //设置当前页的title document.title = to.meta.title; if (to.path === '/login' && localStorage.getItem('token')) { next('/'); } console.log(registerRouteFresh); //如果首次或者刷新界面,next(...to, replace: true)会循环遍历路由, //如果to找不到对应的路由那么他会再执行一次beforeEach((to, from, next))直到找到对应的路由, //我们的问题在于页面刷新以后异步获取数据,直接执行next()感觉路由添加了但是在next()之后执行的, //所以我们没法导航到相应的界面。这里使用变量registerRouteFresh变量做记录,直到找到相应的路由以后,把值设置为false然后走else执行next(),整个流程就走完了,路由也就添加完了。 if (registerRouteFresh) { //设置路由 const accessRoutes = await store.dispatch('generateRoutes', 'admin'); let errorPage = { path: '*', name: '404', component: () => import('../views/404.vue'), }; // 将404添加进去 // 现在才添加的原因是:作为一级路由,当刷新,动态路由还未加载,路由就已经做了匹配,找不到就跳到了404 router.addRoute({ ...errorPage }); accessRoutes.forEach((item: RouteConfig) => { router.addRoute(item); }); //获取路由配置 console.log(router.getRoutes()); //通过next({...to, replace})解决刷新后路由失效的问题 next({ ...to, replace: true }); registerRouteFresh = false; } else { next(); } next(); }); export default router;
菜单权限
路由遍历,通过store路由权限中的permission.state.routes去做处理
按钮权限
准备:存储按钮标识
//地址:store/modules/user import { userInfo, } from '@/api' const user = { state: { role: 'admin', mockButton: { 'btn:access:createUser': 'show', 'btn:access:editUser': 'show' } }, //更改 Vuex 的 store 中的状态的唯一方法是提交 mutation mutations: { change_role: (state, data) => { state.role = data.role }, change_btn: (state, data) => { state.mockButton = data.mockButton } }, } export default user
指令
通过模拟传入按钮标识的属性,去判断按钮是否隐藏或者禁用
//地址:directive/permission/index import permission from './permissionBtn' const install = function(Vue) { Vue.directive('permission', permission) } if (window.Vue) { window['permission'] = permission Vue.use(install); // eslint-disable-line } permission.install = install export default permission
//地址:directive/permission/permissionBtn import store from '@/store' function checkPermission(el, binding) { const { value } = binding const roles = store.getters && store.getters.role // 获取模拟权限按钮标识 const mockButton = store.getters && store.getters.mockButton // 设置按钮属性 if (mockButton[value] === 'disabled') { el.disabled = true el.setAttribute('disabled', true) } if (mockButton[value] === 'hidden') { el.style.display = 'none' } if (mockButton[value] === 'show') { el.style.display = 'block' el.disabled = false } // throw new Error(`need roles! Like v-permission="['admin','editor']"`) } export default { inserted(el, binding) { checkPermission(el, binding) }, update(el, binding) { checkPermission(el, binding) } }
//应用
<template> <div> <a-button @click="changeRole">切换角色</a-button> <span>当前角色:{{ role }}</span> <!-- 注意一定要加disabled属性,才能设置它的disabled值 --> <a-button :disabled="false" v-permission="'btn:access:createUser'"> 新建用户 </a-button> <a-button :disabled="false" v-permission="'btn:access:editUser'"> 编辑用户 </a-button> </div> </template> <script lang='ts'> import { Vue, Component, Watch } from "vue-property-decorator"; import permission from "@/directive/permission/index.js"; // 权限判断指令 // import checkPermission from '@/utils/permission' // 权限判断函数 @Component({ directives: { permission, }, computed: { role() { return this.$store.getters.role; }, }, }) export default class Access extends Vue { get role() { return this.$store.getters.role; } changeRole() { //设置按钮权限 this.$store.commit("change_btn", { mockButton: this.role === "admin" ? { "btn:access:createUser": "hidden", "btn:access:editUser": "disabled", } : { "btn:access:createUser": "show", "btn:access:editUser": "show", }, }); //设置角色 this.$store.commit("change_role", { role: this.role === "admin" ? "edit" : "admin", }); } } </script>
函数
/** * @param {Array} value * @returns {Boolean} * @example see @/views/permission/directive.vue * 除了使用指令,也可以使用函数 */ export default function checkPermission(value) { if (value && value instanceof Array && value.length > 0) { const roles = store.getters && store.getters.roles const permissionRoles = value const hasPermission = roles.some(role => { return permissionRoles.includes(role) }) return hasPermission } console.error(`need roles! Like v-permission="['admin','editor']"`) return false }
<template> <div> <a-button v-if="hasPerms('btn:access:createUser')" :disable="hasPerms('btn:access:createUser')" > 新建用户 </a-button> <a-button v-if="hasPerms('btn:access:editUser')" :disable="hasPerms('btn:access:editUser')" > 编辑用户 </a-button> </div> </template> <script lang='ts'> import { Vue, Component, Watch } from "vue-property-decorator"; import checkPermission from "@/utils/permission"; // 权限判断函数 @Component export default class Access extends Vue { hasPerms(params) { return checkPermission(params); } } </script>
加载全部内容