Vue 前端权限控制的优化改进版

1、前言

之前《Vue前端访问控制方案 》一文中提出,使用class=”permissions”结合元素id来标识权限控制相关的dom元素,并通过公共方法checkRights来设置dom元素的可见属性,在实际使用中存在下列问题:

  • checkRights指定上级节点的domKey,结果document.getElementsByClassName获取了更上级的节点或其它子树的节点,没在指定上级节点下,结果节点没找到,导致错误禁用其它节点的权限。
  • style.display与v-if存在可见属性冲突。
  • 更为致命的是,document.getElementsByClassName找不到插槽的节点,如下列形式:

综上所述问题,因此需要对方案进行优化改进。

2、新的方案

借鉴v-permission的Vue指令方法,并且不再使用可见属性,而是移除无权限节点的dom元素。具体方案如下:

为区别”v-permission”及”:v-permission”,这里使用v-permissions。

创建/src/common/permissions.js文件,代码如下:

import TreeNode from './treeNode.js'

/**
 * 对使用v-permissions指令的dom元素,检查权限;如果无权限,则移除该元素
 * 绑定参数形式:
 *  v-permissions 无参数值形式,表示不指定上级节点的domKey
 *  v-permissions="''",设置空串,注意里面需要包含单引号,也是无参数
 *  v-permissions="'someSuperDomkey'",设置上级节点的domKey,注意里面需要包含单引号
 * @param {element对象} el
 * @param {绑定参数} binding
 */
function checkRights(el,binding){
  // 确保权限树已经加载
  if (TreeNode.rightsTree == null){
    let rights = localStorage.getItem('rights');
    if (rights === null || rights === ''){
      // 没有权限树,移除当前节点
      if(el.parentNode){
        el.parentNode.removeChild(el);
      }
      return;
    }
    // 加载权限树
    TreeNode.rightsTree = TreeNode.loadData(rights);
  }

  // 获取dom元素的id
  var elementId = el.id;
  if (elementId == undefined)
  {
    console.log("Format error! Without id property of the element with v-permissions:" + el);
    return;
  }

  // 获取上级节点的domkey
  //console.log(binding);
  var superDomkey = binding.value;
  var superNode = null;
  if(superDomkey != undefined && superDomkey != ""){
    // 如果指定上级节点,先查找上级节点
    superNode = TreeNode.lookupNodeByDomkey(TreeNode.rightsTree, superDomkey);
    if (superNode == null){
      // 上级key未找到,设置错误
      console.log("Wrong superDomkey value for element:" + el);
      // 忽略上级节点
    }
  }

  // 设置搜索的根节点
  var rootNode = null;
  if (superNode == null){
    // 上级节点为空
    rootNode = TreeNode.rightsTree;
  } else{
    rootNode = superNode;
  }

  // 查找当前节点
  var node = null;
  node = TreeNode.lookupNodeByDomkey(rootNode, elementId);
  if(node == null){
    // 如果未在权限树中找到此节点,表示没有权限
    // 移除此element对象
    if(el.parentNode){
      el.parentNode.removeChild(el);
    }
  }
}

export default {
  inserted(el,binding) {
    checkRights(el,binding)
  },
  update(el,binding) {
    checkRights(el,binding)
  }
}

在main.js中,注册该指令。main.js代码如下:

// The Vue build version to load with the import command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import md5 from 'js-md5';
import axios from 'axios'
import VueAxios from 'vue-axios'
import TreeNode_ from './common/treeNode.js'
import CommonFuncs_ from './common/commonFuncs.js'
import instance_ from './api/index.js'
import global_ from './common/global.js'
import permissions from './common/permissions.js'

Vue.use(VueAxios,axios)
Vue.prototype.$md5 = md5
Vue.prototype.TreeNode = TreeNode_
Vue.prototype.$baseUrl = process.env.API_ROOT
Vue.prototype.instance = instance_  //axios实例
Vue.prototype.global = global_
Vue.prototype.commonFuncs = CommonFuncs_

Vue.use(ElementUI)
Vue.config.productionTip = false

// 注册一个全局自定义指令 v-permissions
Vue.directive('permissions', permissions)

/* eslint-disable no-new */
var vue = new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '',
  render:h=>h(App)
})

export default vue

在commonFuncs.js文件中,删除checkRights方法代码,因为不再调用此方法了。

原来在App.vue和其它vue文件中调用checkRights方法的代码,也删除。

dom元素如果需要进行权限控制,则使用v-permissions指令,同时还要用id属性,匹配约定的domKey。这样就行了,无需编写其它javascript代码。

App.vue文件,代码如下:


import left from './components/Left.vue'

export default {
  name: 'App',
  components: {
    left: left
  },
  data(){
    return {
      collpaseWidth:200
    }
  },
  mounted:function(){

  },
  methods: {

  }
}

#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 20px;
}

.el-main {
  padding-top : 0px;
}

现在不需要任何权限控制的代码了。

侧边导航栏组件Left.vue文件,代码如下:


                首页

            用户管理

                  用户管理

                  修改密码

              问卷内容管理

            问卷发布管理

                  发布问卷查询

                  发布任务查询

              答卷管理

  /* 去掉右边框 */
  .el-menu {
    border-right: none;
  }

  .el-submenu {
    background-color: rgb(231, 235, 220) ;
  }

注意,需要权限控制的dom元素,都有v-permissions,并且有id的值。

业务模块vue模板示例,代码如下:


            用户管理 / 用户管理

              添加用户

              查询

                {{userTypeMap.get(scope.row.userType).itemValue}}

                {{genderMap.get(scope.row.gender).itemValue}}

                {{deptMap.get(scope.row.deptId).itemValue}}

                {{userStatusMap.get(scope.row.deleteFlag).itemValue}}

权限控制项,都设置了:v-permissions=”‘userManagementSub'”,指明了上级节点的domkey为userManagementSub。无需其它javascipt调用控制代码。

还有,id=”disableUser”和id=”enableUser”的元素,都使用了v-if指令,现在也不会有可见属性的冲突。

利用Vue的指令,使得权限控制表述更为简洁,无需其它javascript脚本,且解决了class被屏蔽的问题。另外,使用移除元素的方法,避免了与v-if的可见属性的冲突。

经测试,达到了权限控制的效果。

如果权限动态发生改变,只需刷新页面,将重构页面,无需担心移除的节点彻底消失。

Original: https://www.cnblogs.com/alabo1999/p/14976481.html
Author: 阿拉伯1999
Title: Vue 前端权限控制的优化改进版

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/643870/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球