[前端] vue2模拟vue-element-admin手写角色权限的实现

2476 0
Honkers 2022-10-21 15:31:35 | 显示全部楼层 |阅读模式
目录

    权限
      路由权限
        store存储路由router添加路由
      菜单权限按钮权限
        准备:存储按钮标识指令函数




权限


路由权限

    静态路由:固定的路由,没有权限。如login页面动态路由:根据不同的角色,后端返回不同的路由接口。通过meta中的roles去做筛选

store存储路由
  1. //地址:store/modules/permission
  2. import { routes as constantRoutes } from '@/router'
  3. // 根据meta.roles去判断该角色是否有路由权限
  4. function hasPermission(oles, route) {
  5.   if (route.meta && route.meta.roles) {
  6.     return route.meta.roles.some(val => val === roles)
  7.   }
  8.   return true
  9. }
  10. /**
  11. * 递归动态路由
  12. * @param routes 动态路由
  13. * @param roles 角色
  14. */
  15. export function filterAsyncRoutes(routes, roles) {
  16.   const res = []
  17.   routes.forEach(route => {
  18.     const tmp = { ...route }
  19.     if (hasPermission(roles, tmp)) {
  20.       if (tmp.children) {
  21.         //后台传来的路由字符串,转换为组件对象
  22.         //       let a = `../views/${route.component}`;
  23.         //       route.component = () => import(a); // 导入组件
  24.         tmp.children = filterAsyncRoutes(tmp.children, roles)
  25.       }
  26.       res.push(tmp)
  27.     }
  28.   })
  29.   return res
  30. }
  31. //模拟后端传过来的路由
  32. export const asyncRoutes = [
  33.   {
  34.     path: '/',
  35.     name: 'home',
  36.     redirect: '/PickupTask',
  37.     meta: {
  38.       title: '首页',
  39.       //纯前端去做动态路由
  40.       roles: ['admin']
  41.     },
  42.     component: () => import('@/views/HomeView.vue'),
  43.     children: [
  44.       {
  45.         path: 'PickupTask',
  46.         name: 'PickupTask',
  47.         meta: {
  48.           title: 'PickupTask',
  49.         },
  50.         component: () => import('@/views/Sd/PickupTask.vue'),
  51.       },
  52.       {
  53.         path: 'access',
  54.         hidden: true,
  55.         component: () => import('@/views/demo/Access.vue'),
  56.         meta: {
  57.           title: 'access',
  58.           roles: ['admin'],
  59.           //按钮权限标识
  60.           button: {
  61.             'btn:access:createUser': 'hidden',
  62.             'btn:access:editUser': 'disable'
  63.           },
  64.         },
  65.       },
  66.     ],
  67.   }
  68. ]
  69. const permisssion = {
  70.   // namespaced: true, -> store.dispatch('permisssion/generateRoutes', 'admin');
  71.   state: {
  72.     //静态路由+动态路由
  73.     routes: [],
  74.     //动态路由
  75.     addRoutes: []
  76.   },
  77.   mutations: {
  78.     SET_ROUTES: (state, routes) => {
  79.       state.addRoutes = routes
  80.       state.routes = constantRoutes.concat(routes)
  81.     }
  82.   },
  83.   actions: {
  84.     generateRoutes({ commit }, roles) {
  85.       return new Promise(resolve => {
  86.         let accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
  87.         commit('SET_ROUTES', accessedRoutes)
  88.         resolve(accessedRoutes)
  89.       })
  90.     }
  91.   }
  92. }
  93. export default permisssion
复制代码
router添加路由

将store中的动态路由使用addRoute添加(最新版本去掉了addRoutes只能使用addRoute添加路由)。
  1. //地址:router/index
  2. import Vue from 'vue';
  3. import VueRouter, { RouteConfig } from 'vue-router';
  4. import store from '@/store';
  5. Vue.use(VueRouter);
  6. const isProd = process.env.NODE_ENV === 'production';
  7. const routerContext = require.context('./', true, /index.js$/);
  8. //静态路由
  9. export let routes: any = [];
  10. routerContext.keys().forEach((route) => {
  11.   // route就是路径
  12.   // 如果是根目录的index不做处理
  13.   if (route.startsWith('./index')) {
  14.     return;
  15.   }
  16.   const routerModule = routerContext(route);
  17.   routes = [...routes, ...(routerModule.default || routerModule)];
  18. });
  19. // 创建 router 实例,然后传 `routes` 配置
  20. const router = new VueRouter({
  21.   mode: 'history',
  22.   base: isProd ? '/vue-demo/' : process.env.BASE_URL,
  23.   routes,
  24.   scrollBehavior(to, from, savedPosition) {
  25.     if (to.hash) {
  26.       return {
  27.         selector: to.hash,
  28.       };
  29.     }
  30.   },
  31. });
  32. let registerRouteFresh = true;
  33. /**
  34. * 全局全局前置守卫
  35. * to : 将要进入的目标路由对象
  36. * from : 即将离开的目标路由对象
  37. */
  38. router.beforeEach(async (to: any, from, next) => {
  39.   //设置当前页的title
  40.   document.title = to.meta.title;
  41.   if (to.path === '/login' && localStorage.getItem('token')) {
  42.     next('/');
  43.   }
  44.   console.log(registerRouteFresh);
  45.   //如果首次或者刷新界面,next(...to, replace: true)会循环遍历路由,
  46.   //如果to找不到对应的路由那么他会再执行一次beforeEach((to, from, next))直到找到对应的路由,
  47.   //我们的问题在于页面刷新以后异步获取数据,直接执行next()感觉路由添加了但是在next()之后执行的,
  48.   //所以我们没法导航到相应的界面。这里使用变量registerRouteFresh变量做记录,直到找到相应的路由以后,把值设置为false然后走else执行next(),整个流程就走完了,路由也就添加完了。
  49.   if (registerRouteFresh) {
  50.     //设置路由
  51.     const accessRoutes = await store.dispatch('generateRoutes', 'admin');
  52.     let errorPage = {
  53.       path: '*',
  54.       name: '404',
  55.       component: () => import('../views/404.vue'),
  56.     };
  57.     // 将404添加进去
  58.     // 现在才添加的原因是:作为一级路由,当刷新,动态路由还未加载,路由就已经做了匹配,找不到就跳到了404
  59.     router.addRoute({ ...errorPage });
  60.     accessRoutes.forEach((item: RouteConfig) => {
  61.       router.addRoute(item);
  62.     });
  63.     //获取路由配置
  64.     console.log(router.getRoutes());
  65.     //通过next({...to, replace})解决刷新后路由失效的问题
  66.     next({ ...to, replace: true });
  67.     registerRouteFresh = false;
  68.   } else {
  69.     next();
  70.   }
  71.   next();
  72. });
  73. export default router;
复制代码
菜单权限

路由遍历,通过store路由权限中的permission.state.routes去做处理

按钮权限


准备:存储按钮标识
  1. //地址:store/modules/user
  2. import {
  3.   userInfo,
  4. } from '@/api'
  5. const user = {
  6.   state: {
  7.     role: 'admin',
  8.     mockButton: {
  9.       'btn:access:createUser': 'show',
  10.       'btn:access:editUser': 'show'
  11.     }
  12.   },
  13.   //更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
  14.   mutations: {
  15.     change_role: (state, data) => {
  16.       state.role = data.role
  17.     },
  18.     change_btn: (state, data) => {
  19.       state.mockButton = data.mockButton
  20.     }
  21.   },
  22. }
  23. export default user
复制代码
指令

通过模拟传入按钮标识的属性,去判断按钮是否隐藏或者禁用
  1. //地址:directive/permission/index
  2. import permission from './permissionBtn'
  3. const install = function(Vue) {
  4.   Vue.directive('permission', permission)
  5. }
  6. if (window.Vue) {
  7.   window['permission'] = permission
  8.   Vue.use(install); // eslint-disable-line
  9. }
  10. permission.install = install
  11. export default permission
复制代码
  1. //地址:directive/permission/permissionBtn
  2. import store from '@/store'
  3. function checkPermission(el, binding) {
  4.   const { value } = binding
  5.   const roles = store.getters && store.getters.role
  6.   // 获取模拟权限按钮标识
  7.   const mockButton = store.getters && store.getters.mockButton
  8.   // 设置按钮属性
  9.   if (mockButton[value] === 'disabled') {
  10.     el.disabled = true
  11.     el.setAttribute('disabled', true)
  12.   }
  13.   if (mockButton[value] === 'hidden') {
  14.     el.style.display = 'none'
  15.   }
  16.   if (mockButton[value] === 'show') {
  17.     el.style.display = 'block'
  18.     el.disabled = false
  19.   }
  20.   // throw new Error(`need roles! Like v-permission="['admin','editor']"`)
  21. }
  22. export default {
  23.   inserted(el, binding) {
  24.     checkPermission(el, binding)
  25.   },
  26.   update(el, binding) {
  27.     checkPermission(el, binding)
  28.   }
  29. }
复制代码
//应用
  1. <template>
  2.   <div>
  3.     <a-button @click="changeRole">切换角色</a-button>
  4.     <span>当前角色:{{ role }}</span>
  5.     <!-- 注意一定要加disabled属性,才能设置它的disabled值 -->
  6.     <a-button :disabled="false" v-permission="'btn:access:createUser'">
  7.       新建用户
  8.     </a-button>
  9.     <a-button :disabled="false" v-permission="'btn:access:editUser'">
  10.       编辑用户
  11.     </a-button>
  12.   </div>
  13. </template>
  14. <script lang='ts'>
  15. import { Vue, Component, Watch } from "vue-property-decorator";
  16. import permission from "@/directive/permission/index.js"; // 权限判断指令
  17. // import checkPermission from '@/utils/permission' // 权限判断函数
  18. @Component({
  19.   directives: {
  20.     permission,
  21.   },
  22.   computed: {
  23.     role() {
  24.       return this.$store.getters.role;
  25.     },
  26.   },
  27. })
  28. export default class Access extends Vue {
  29.   get role() {
  30.     return this.$store.getters.role;
  31.   }
  32.   changeRole() {
  33.     //设置按钮权限
  34.     this.$store.commit("change_btn", {
  35.       mockButton:
  36.         this.role === "admin"
  37.           ? {
  38.               "btn:access:createUser": "hidden",
  39.               "btn:access:editUser": "disabled",
  40.             }
  41.           : {
  42.               "btn:access:createUser": "show",
  43.               "btn:access:editUser": "show",
  44.             },
  45.     });
  46.     //设置角色
  47.     this.$store.commt("change_role", {
  48.       role: this.role === "admin" ? "edit" : "admin",
  49.     });
  50.   }
  51. }
  52. </script>
复制代码
函数
  1. /**
  2. * @param {Array} value
  3. * @returns {Boolean}
  4. * @example see @/views/permission/directive.vue
  5. * 除了使用指令,也可以使用函数
  6. */
  7. export default function checkPermission(value) {
  8.   if (value && value instanceof Array && value.length > 0) {
  9.     const roles = store.getters && store.getters.roles
  10.     const permissionRoles = value
  11.     const hasPermission = roles.some(role => {
  12.       return permissionRoles.includes(role)
  13.     })
  14.     return hasPermission
  15.   }
  16.     console.error(`need roles! Like v-permission="['admin','editor']"`)
  17.     return false
  18. }
复制代码
  1. <template>
  2.   <div>
  3.     <a-button
  4.       v-if="hasPerms('btn:access:createUser')"
  5.       :disable="hasPerms('btn:access:createUser')"
  6.     >
  7.       新建用户
  8.     </a-button>
  9.     <a-button
  10.       v-if="hasPerms('btn:access:editUser')"
  11.       :disable="hasPerms('btn:access:editUser')"
  12.     >
  13.       编辑用户
  14.     </a-button>
  15.   </div>
  16. </template>
  17. <script lang='ts'>
  18. import { Vue, Component, Watch } from "vue-property-decorator";
  19. import checkPermission from "@/utils/permission"; // 权限判断函数
  20. @Component
  21. export default class Access extends Vue {
  22.   hasPerms(params) {
  23.     return checkPermission(params);
  24.   }
  25. }
  26. </script>
复制代码
到此这篇关于vue2模拟vue-element-admin手写角色权限的实现的文章就介绍到这了,更多相关vue2 角色权限内容请搜索中国红客联盟以前的文章或继续浏览下面的相关文章希望大家以后多多支持中国红客联盟!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Honkers

特级红客

关注
  • 3160
    主题
  • 36
    粉丝
  • 0
    关注
这家伙很懒,什么都没留下!

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行