研发笔记——vue2项目添加权限管理

需求背景

后台系统经常需要给用户划分不同的角色,不同角色的操作权限不同,这样可以有效避免人为的误操作。
项目框架为 Vue2+Element

实现方案

盘点项目中需要权限控制的地方,可以归为三类。

  1. 整体页面——通过后端接口控制
  2. 侧边菜单栏——路由中添加权限标识
  3. 页面中的组件元素——vue自定义指令
1. 整体页面控制

对于整个页面的控制,前端没有专门做限制。而是通过后端在当前页面接口返回无权限错误码,前端拿到错误码后,将页面重定向到一个无权限的落地页。

2. 侧边栏控制

侧边菜单栏是通过router数组遍历出来的,要实现对应角色只能看到相应权限的菜单,就需要在菜单渲染之前进行过滤。

  {
    path: '/equipment/info',
    name: 'Equipment',
    component: () => import('@/views/equipment/index.vue'),
    icon: 'icon-equipment',
    permission: 'p_equipment', //在路由结构中添加对应的权限标识
    meta: {
      title: 'menu.equipment',
      keepAlive: true,
    },
  },

后端需要提供一个根据角色查询权限的接口,在main.js文件中调用,根据返回的权限列表对路由进行过滤

getPermissionRouter() {
  getPermission(roleId).then((res) => {
    if (res.code === 0) {
      // 过滤没有权限展示的路由,侧边栏渲染时会忽略hidden为true的路由
      if (res.data.permission_list) {
        this.$router.options.routes.forEach((route) => {
          if (route.permission) {
            if (Array.isArray(route.permission)) {
              route.hidden = !res.data.permission_list.filter((item) => route.permission.includes(item)).length;
            } else {
              route.hidden = !res.data.permission_list.find((item) => item === route.permission);
            }
          }
        });
      }
    }
  });
}

这里只列出了核心的过滤代码,实际还会有很多优化逻辑,比如只有角色变化才进行过滤等

3. 页面组件元素控制

对于页面上的文案、图片、按钮、输入框等元素的权限,如果每一个都用v-ifv-show来判断,工作量非常大。我这里采用了vue中的自定义指令来实现。

首先新建一个permission.js文件,这里我将DOM元素分为查看编辑两种。

// permission.js

import store from '@/store';

/**
 * @param binding.arg arg.show表示是否能够展示,arg.edit表示是否能够编辑
 * @param binding.value value表示指令的绑定值,根据绑定的元素位置传递,本次传递粒度仅页面
 */
function checkPermission(el, binding) {
  const { value, arg } = binding;
  // admin或未传权限标识则退出
  if (!value || store.state.roleId === '1') {
    return;
  }
  // permissionList是后端返回的权限列表,判断元素携带的权限标识是否在列表中
  let key = store.state.permissionList.includes(value);
  if (arg === 'show') {
    if (!key) {
      el.parentNode && el.parentNode.removeChild(el);
    }
  } else if (arg === 'edit') {
    if (!key) {
      el.style.pointerEvents = 'none';
      disabledNode(el); // 操作DOM节点将其置为不可用状态
    }
  }
}

function disabledNode(node) {
  if (node.classList) {
    node.classList.add('is-disabled');
    if (Array.from(node.classList).includes('el-input__suffix-inner')) {
      const childs = node.childNodes;
      childs.forEach(element => node.parentNode && node.parentNode.appendChild(element));
    }
  }
  if (node.nodeName === 'INPUT' || node.nodeName === 'TEXTAREA') {
    node.setAttribute('disabled', 'disabled');
    return;
  } else if (node.nodeName === 'BUTTON') {
    node.disabled = true;
    return;
  } else {
    node.childNodes.length > 0 && node.childNodes.forEach(item => disabledNode(item));
  }
}

export default {
  inserted(el, binding) {
    checkPermission(el, binding);
  },
  update(el, binding) {
    checkPermission(el, binding);
  },
};

// main.js
import permission from '@/utils/permission.js';

Vue.directive('permission', permission); // 注册自定义指令

使用方式

<el-button v-permission:edit="'xxx'">click</el-button> 
<span v-permission:show="'yyy'">hello</span>
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值