利用Vue的指令,使得权限控制表述更为简洁,无需其它javascript脚本,且解决了class被屏蔽的问题 。另外,使用移除元素的方法,避免了与v-if的可见属性的冲突 。1、前言??之前《Vue前端访问控制方案 》一文中提出,使用class=“permissions”结合元素id来标识权限控制相关的dom元素,并通过公共方法checkRights来设置dom元素的可见属性,在实际使用中存在下列问题:
- checkRights指定上级节点的domKey,结果document.getElementsByClassName获取了更上级的节点或其它子树的节点,没在指定上级节点下,结果节点没找到,导致错误禁用其它节点的权限 。
- style.display与v-if存在可见属性冲突 。
- 更为致命的是,document.getElementsByClassName找不到插槽的节点,如下列形式:
<el-table-column label="操作"><template slot-scope="scope"><el-tooltip class="item,permissions" effect="dark" content="编辑" id="editUser" placement="left-start"><el-button size="mini" type="primary" icon="el-icon-edit" circle @click="editUser(scope.row)"></el-button></el-tooltip><el-tooltip class="item,permissions" effect="dark" content="禁用" id="disableUser"placement="left-start" v-if="!scope.row.deleteFlag"><el-button size="mini" type="primary" icon="el-icon-lock" circle @click="disableUser(scope.row)"></el-button></el-tooltip><el-tooltip class="item,permissions" effect="dark" content="启用" id="enableUser"placement="left-start"v-if="scope.row.deleteFlag"><el-button size="mini" type="primary" icon="el-icon-unlock" circle @click="enableUser(scope.row)"></el-button></el-tooltip></template></el-table-column>??此时,document.getElementsByClassName方法找不到class中有permissions的对象 。Vue与JQuery的思想有很大不同 。??综上所述问题,因此需要对方案进行优化改进 。
2、新的方案??借鉴v-permission的Vue指令方法,并且不再使用可见属性,而是移除无权限节点的dom元素 。具体方案如下:
2.1、定义v-permissions指令??为区别"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元素的idvar 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)}}2.2、注册该指令??在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 = md5Vue.prototype.TreeNode = TreeNode_Vue.prototype.$baseUrl = process.env.API_ROOTVue.prototype.instance = instance_//axios实例Vue.prototype.global = global_Vue.prototype.commonFuncs = CommonFuncs_Vue.use(ElementUI)Vue.config.productionTip = false// 注册一个全局自定义指令 v-permissionsVue.directive('permissions', permissions)/* eslint-disable no-new */var vue = new Vue({el: '#app',router,store,components: { App },template: '<App/>',render:h=>h(App)})export default vue2.3、删除checkRights方法??在commonFuncs.js文件中,删除checkRights方法代码,因为不再调用此方法了 。??原来在App.vue和其它vue文件中调用checkRights方法的代码,也删除 。
2.4、模板文件示例??dom元素如果需要进行权限控制,则使用v-permissions指令,同时还要用id属性,匹配约定的domKey 。这样就行了,无需编写其它javascript代码 。
2.4.1、App.vue文件??App.vue文件,代码如下:
<template><div id="app"><!-- 其他页 --><el-container style="min-height: calc(100% - 50px);" v-if="$route.meta.keepAlive"><!-- 无头部导航栏 --><el-container><el-aside :style="{width:collpaseWidth}"><!-- 侧边栏 --><keep-alive><left></left></keep-alive></el-aside><el-main><!-- Body --><router-view></router-view></el-main></el-container><!-- 无足部 --></el-container><!-- 登录页 --><router-view v-if="!$route.meta.keepAlive"></router-view></div></template><script>import left from './components/Left.vue'export default {name: 'App',components: {left: left},data(){return {collpaseWidth:200}},mounted:function(){},methods: {}}</script><style>#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;}</style>??现在不需要任何权限控制的代码了 。2.4.2、Left.vue文件??侧边导航栏组件Left.vue文件,代码如下:
<template><div class="left-sidebar"><el-menu :default-openeds="['1']" style="background:#F0F6F6;"><el-submenu index="1"><el-menu-item-group ><el-menu-item index="1-1"><router-link class="menu" tag="li" to="/home" exact-active-class="true"id="homeMenu" active-class="_active"><i class="el-icon-s-home"></i>首页</router-link></el-menu-item><el-submenu index="1-2" v-permissions id="userManagementMain"><template slot="title" ><i class="el-icon-user-solid"></i>用户管理</template><el-menu-item index="1-2-1" v-permissions id="userManagementSub"><router-link class="menu" tag="li" to="/userManagement"><i class="el-icon-user"></i>用户管理</router-link></el-menu-item><el-menu-item index="1-2-2" v-permissions id="changePassword"><router-link class="menu"tag="li" to="/changePassword"><i class="el-icon-key"></i>修改密码</router-link></el-menu-item></el-submenu><el-menu-item index="1-3" v-permissions id="questionnaireManagement"><router-link class="menu" tag="li" to="/questionnaireManagement"><i class="el-icon-document"></i>问卷内容管理</router-link></el-menu-item><el-submenu index="1-4" v-permissions id="issueManagementMain"><template slot="title"><i class="el-icon-message"></i>问卷发布管理</template><el-menu-item index="1-4-1" v-permissions id="issueManagementSub"><router-linkclass="menu" tag="li" to="/issueManagement"><i class="el-icon-phone"></i>发布问卷查询</router-link></el-menu-item><el-menu-item index="1-4-2" v-permissions id="issueTaskQuery"><router-link class="menu" tag="li" to="/issueTaskQuery"><i class="el-icon-tickets"></i>发布任务查询</router-link></el-menu-item></el-submenu><el-menu-item index="1-5" v-permissions id="answerSheetManagement"><router-link class="menu" tag="li" to="/answerSheetManagement"><i class="el-icon-receiving"></i>答卷管理</router-link></el-menu-item></el-menu-item-group></el-submenu></el-menu></div></template><style>/* 去掉右边框 */.el-menu {border-right: none;}.el-submenu {background-color: rgb(231, 235, 220) ;}</style>??注意,需要权限控制的dom元素,都有v-permissions,并且有id的值 。2.4.3、业务模块vue模板示例??业务模块vue模板示例,代码如下:
<template><div id="contentwrapper"><el-form ref="form" :model="formData" label-width="80px"><el-card><el-row><!--占整行--><el-col :span="24"><h5 class="heading" align=left>用户管理 / 用户管理</h5><!-- 分隔线 --><el-divider></el-divider></el-col></el-row><el-row><el-col align="left" :span="6"><el-button type="primary" v-permissions="'userManagementSub'" id="addUser" size="small" @click="addUser"><i class="el-icon-circle-plus"></i>添加用户</el-button></el-col><!-- 查询条件 --><el-col align="left" :span="6"><el-form-item label="用户类型:" label-width="100px"><el-select v-model="formData.userTypeLabel" size="small" @change="selectUserType"><el-optionv-for="(item,index) in userTypeList":key="index":label="item.itemValue":value="https://tazarkount.com/read/item"/></el-select></el-form-item></el-col><el-col :span="6"><el-form-item label="用户状态:" label-width="100px"><el-select v-model="formData.userStatusLabel" size="small" @change="selectUserStatus"><el-optionv-for="item in userStatusList":key="item.itemKey":label="item.itemValue":value="https://tazarkount.com/read/item"/></el-select></el-form-item></el-col><el-col align="right" :span="6"><el-button type="primary" v-permissions="'userManagementSub'" id="queryUser" size="small" @click="queryUsers"><i class="el-icon-search"></i>查询</el-button></el-col></el-row><!-- 用户列表数据 --><el-table :data="https://tazarkount.com/read/userInfoList" border stripe :row-style="{height:'30px'}":cell-style="{padding:'0px','text-align':'center'}" style="font-size: 10px":header-cell-style="{'text-align':'center'}"><el-table-column label="用户ID" width="60px" prop="userId"></el-table-column><el-table-column label="用户类型" width="100px" prop="userType"><template slot-scope="scope"><span v-if="userTypeMap.get(scope.row.userType) != null">{{userTypeMap.get(scope.row.userType).itemValue}}</span></template></el-table-column><el-table-column label="登录名" width="100px" prop="loginName"></el-table-column><el-table-column label="真实名称" width="80px" prop="userName"></el-table-column><el-table-column label="手机号码" width="100px" prop="phoneNumber"></el-table-column><el-table-column label="EMail" prop="email" width="160px"></el-table-column><el-table-column label="性别" width="60px" prop="gender"><template slot-scope="scope"><span v-if="genderMap.get(scope.row.gender) != null">{{genderMap.get(scope.row.gender).itemValue}}</span></template></el-table-column><el-table-column label="部门" width="100px" prop="deptId"><template slot-scope="scope"><span v-if="deptMap.get(scope.row.deptId) != null">{{deptMap.get(scope.row.deptId).itemValue}}</span></template></el-table-column><el-table-column label="状态" width="60px" prop="deleteFlag"><template slot-scope="scope"><span v-if="userStatusMap.get(scope.row.deleteFlag) != null">{{userStatusMap.get(scope.row.deleteFlag).itemValue}}</span></template></el-table-column><el-table-column label="角色" width="100px" prop="roles" :formatter="rolesFormatter"></el-table-column><el-table-column label="操作"><template slot-scope="scope"><el-tooltip class="item" effect="dark" content="编辑" v-permissions="'userManagementSub'" id="editUser" placement="left-start"><el-button size="mini" type="primary" icon="el-icon-edit" circle @click="editUser(scope.row)"></el-button></el-tooltip><el-tooltip class="item" effect="dark" content="禁用" v-permissions="'userManagementSub'" id="disableUser"placement="left-start" v-if="!scope.row.deleteFlag"><el-button size="mini" type="primary" icon="el-icon-lock" circle @click="disableUser(scope.row)"></el-button></el-tooltip><el-tooltip class="item" effect="dark" content="启用" v-permissions="'userManagementSub'" id="enableUser"placement="left-start"v-if="scope.row.deleteFlag"><el-button size="mini" type="primary" icon="el-icon-unlock" circle @click="enableUser(scope.row)"></el-button></el-tooltip></template></el-table-column></el-table><!-- 分页区域 --><el-pagination @size-change="handleSizeChange"@current-change="handleCurrentChange" :current-page="formData.pageInfo.pagenum":page-sizes="[5, 10, 15, 20]" :page-size="formData.pageInfo.pagesize"layout="total, sizes, prev, pager, next, jumper" :total="formData.pageInfo.total"background></el-pagination></el-card></el-form><!-- 新增、编辑 --><add-or-edit-user v-if="editVisible" ref="addOrEditUser"></add-or-edit-user></div></template>??权限控制项,都设置了:v-permissions="'userManagementSub'",指明了上级节点的domkey为userManagementSub 。无需其它javascipt调用控制代码 。??还有,id="disableUser"和id="enableUser"的元素,都使用了v-if指令,现在也不会有可见属性的冲突 。
2.5、方案总结??利用Vue的指令,使得权限控制表述更为简洁,无需其它javascript脚本,且解决了class被屏蔽的问题 。另外,使用移除元素的方法,避免了与v-if的可见属性的冲突 。
??经测试,达到了权限控制的效果 。
【Vue 前端权限控制的优化改进版】??如果权限动态发生改变,只需刷新页面,将重构页面,无需担心移除的节点彻底消失 。
作者:阿拉伯1999出处:http://www.cnblogs.com/alabo1999/本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.养成良好习惯,好文章随手顶一下 。
- 春季老年人吃什么养肝?土豆、米饭换着吃
- 三八妇女节节日祝福分享 三八妇女节节日语录
- 老人谨慎!选好你的“第三只脚”
- 校方进行了深刻的反思 青岛一大学生坠亡校方整改校规
- 脸皮厚的人长寿!有这特征的老人最长寿
- 长寿秘诀:记住这10大妙招 100%增寿
- 春季老年人心血管病高发 3条保命要诀
- 眼睛花不花要看四十八 老年人怎样延缓老花眼
- 香槟然能防治老年痴呆症? 一天三杯它人到90不痴呆
- 老人手抖的原因 为什么老人手会抖
