欢迎来到3672js教程,我们关注js教程、js框架、js代码特效等。

vue2模拟vue-element-admin手写角色权限的实现,

3672Js.Com2022-07-28 00:50 来源:未知 阅读:13218 关注度4

vue2模拟vue-element-admin手写角色权限的实现,


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

    权限

    路由权限

    • 静态路由:固定的路由,没有权限。如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>

    到此这篇关于vue2模拟vue-element-admin手写角色权限的实现的文章就介绍到这了,更多相关vue2 角色权限内容请搜索3672js教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持3672js教程!

    您可能感兴趣的文章:
    • 详解利用 Vue.js 实现前后端分离的RBAC角色权限管理

    本站文章为3672js教程网友分享投稿,版权归原作者,欢迎任何形式的转载,但请务必注明出处。同时文章内容如有侵犯了您的权益,请联系我们处理。
    评论已被关闭
    {dede:include filename="foot.htm"/}