Vue2.0权限树组件实现代码
程序员文章站
2022-09-08 22:06:20
项目使用的饿了么的element-ui,权限树使用其树形控件:
...
项目使用的饿了么的element-ui,权限树使用其树形控件:
<el-tree :data="data" ></el-tree>
刚开始没有特殊需求,三级分支,效果看着还可以。但是接下来的新需求:增加页面操作按钮权限,即达到四级分支,同时要求四级权限布局方式为横向,而且操作按钮权限非固定四级树,但是样式要求一致。这样子就很难操作了,如果单单是四级树为横向,还可以调调样式完成。本来想修改element的tree控件源码来实现,网上查了一些资料,还没有很好的办法生成其编译文件。最终决定自己写组件完成上述需求。
先上效果图:
基本可以满足需求,样式稍微比element差点,后期再优化。
组件代码如下:
<template> <li :class="[isbutton, hasborder]" style="list-style:none;"> <span @click="toggle" v-show="model.menulevel!==1" > <i v-if="isfolder" class="icon" :class="[open ? 'folder-open': 'folder']" style="margin-bottom: 3px;"></i> <i v-if="!isfolder" class="icon file-text"></i> <input type="checkbox" class="checkcls" @click.stop="seltree(model)" :id="'menu'+model.id" :class="'group'+label"> {{ model.menuname }} </span> <ul v-show="open" v-if="isfolder"> <tree-menu v-for="(item, index) in model.childnode" :model="item" :key="index" :menulist="menulist" :label="label" :selectkeys="selectkeys" ></tree-menu> </ul> </li> </template> <script type="text/ecmascript-6"> import $ from 'jquery' export default { name: 'treemenu', props: ['model', 'menulist', 'label', 'selectkeys'], data () { return { open: true, // 默认打开彩单树 selallkeys: [] } }, computed: { isfolder: function () { return this.model.childnode && this.model.childnode.length }, isbutton: function () { if (this.model.buttoncontrol === '1') { return 'btncls' } else { return 'menucls' } }, hasborder: function () { if (this.model.menulevel === 1) { return 'blk_border' } } }, methods: { getallkeys () { var keys = [] var objs = $('.group' + this.label + ':checked') for (let i = 0; i < objs.length; i++) { let id = objs[i].id id = id.substring(4) keys.push((id - 0)) // 保存选中菜单id } return keys }, toggle: function () { if (this.isfolder) { this.open = !this.open } }, // 根据id获取menu对象 getmeunbyid (id, allmenulist) { var menu = {} if (allmenulist.id === id) { // 一级菜单 menu = allmenulist } else if (allmenulist.childnode && allmenulist.childnode.length) { // 二级菜单 for (let i = 0; i < allmenulist.childnode.length; i++) { if (allmenulist.childnode[i].id === id) { menu = allmenulist.childnode[i] break } else if (allmenulist.childnode[i].childnode && allmenulist.childnode[i].childnode.length) { // 三级 for (let j = 0; j < allmenulist.childnode[i].childnode.length; j++) { if (allmenulist.childnode[i].childnode[j].id === id) { menu = allmenulist.childnode[i].childnode[j] break } } } } } return menu }, // checkbox点击事件 seltree (model) { var obj = $('#menu' + model.id)[0] // checkbox dom对象 if (obj.checked) { // 选中 // 若存在下级,下级全部选中 if (model.childnode && model.childnode.length) { this.submenusop(model.childnode, 1) } // 若存在上级,确认是否需要选中上级checkbox if (model.supmenuid !== 0 && model.menulevel > 2) { this.supmenusop(model.supmenuid, 1) } } else { // 取消 // 若存在下级,下级全部取消 if (model.childnode && model.childnode.length) { this.submenusop(model.childnode, 0) } // 若存在上级,确认是否需要取消上级checkbox if (model.supmenuid !== 0 && model.menulevel > 2) { this.supmenusop(model.supmenuid, 0) } } this.getallkeys() }, // 下级菜单操作 flag=1为选中,flag=0为取消 submenusop (childnodes, flag) { for (let i = 0; i < childnodes.length; i++) { var menu = childnodes[i] var id = menu.id if (flag === 1) { // 选中 $('#menu' + id)[0].checked = true } else { // 取消 $('#menu' + id)[0].checked = false } if (menu.childnode && menu.childnode.length) { this.submenusop(menu.childnode, flag) } } }, // 上级菜单操作(选中:flag=1,取消:flag=0) supmenusop (id, flag) { var menu = this.getmeunbyid(id, this.menulist) if (menu.childnode && menu.childnode.length) { var childlength = menu.childnode.length // 直接子级个数 var selectcount = 0 for (let i = 0; i < childlength; i++) { let id1 = menu.childnode[i].id if ($('#menu' + id1)[0].checked) { selectcount++ } } if (flag === 1) { // 选中 if (childlength === selectcount) { $('#menu' + id)[0].checked = true if (menu.supmenuid !== 0 && menu.menulevel > 2) { this.supmenusop(menu.supmenuid, flag) } } } else if (flag === 0) { if (childlength !== selectcount) { $('#menu' + id)[0].checked = false if (menu.supmenuid !== 0 && menu.menulevel > 2) { this.supmenusop(menu.supmenuid, flag) } } } } }, // 计算所有下级节点是否全部选中,是返回true,否返回false isallsel (childnodes, selectkeys) { var nodekeys = [] // 选中的id集合 this.addkeys(childnodes, selectkeys, nodekeys) var allkeys = [] this.getnodescount(childnodes, allkeys) if (nodekeys.length === allkeys.length) { return true } else { return false } }, // 计算childnodes下选中的id集合 addkeys (childnodes, selectkeys, arrs) { for (let i = 0; i < childnodes.length; i++) { if (selectkeys.indexof(childnodes[i].id) >= 0) { arrs.push(childnodes[i].id) } if (childnodes[i].childnode && childnodes[i].childnode.length) { this.addkeys(childnodes[i].childnode, selectkeys, arrs) } } }, // 计算childnodes的子级数 getnodescount (childnodes, allkeys) { for (let i = 0; i < childnodes.length; i++) { allkeys.push(childnodes[i].id) if (childnodes[i].childnode && childnodes[i].childnode.length) { this.getnodescount(childnodes[i].childnode, allkeys) } } } }, mounted () { // 禁止复选框的冒泡事件 $("input[type='checkbox']").click(function (e) { e.stoppropagation() }) // 选中菜单使能 if (this.selectkeys instanceof array && this.selectkeys.length > 0 && this.selectkeys.indexof(this.model.id) >= 0) { if (this.model.childnode && this.model.childnode.length && this.model.menulevel !== 1) { // 包含子级,一级菜单除外 // 计算所有子节点是否全部选中 if (this.isallsel(this.model.childnode, this.selectkeys)) { $('#menu' + this.model.id)[0].checked = true } } else { $('#menu' + this.model.id)[0].checked = true } } } } </script> <style> .blk_border{ border:1px solid #d1dbe5; padding-bottom: 15px; } .blk_border ul{ padding-left: 15px; } ul { list-style: none; } i.icon { display: inline-block; width: 15px; height: 15px; background-repeat: no-repeat; vertical-align: middle; } .icon.folder { background-image: url(../../images/close.png); } .icon.folder-open { background-image: url(../../images/open.png); } .tree-menu li { line-height: 1.5; } li.btncls { float: left; margin-right: 10px; } li.menucls { clear: both; line-height:30px; } .checkcls { vertical-align: middle; } .el-tabs__content{ color:#48576a; } </style> 权限树的数据结构有一定要求,比element的tree控件数据结构属性稍多一些,否则实现也不会这么简单了,优化后的权限树数据结构在选中菜单返回上简化了很多,也没有用到vuex。 权限树数据结构为: { 'childnode': [ { 'childnode': [ { 'icon': '', 'id': 242, 'menulevel': 3, 'menuname': '旅游订单', 'menutop': 1, 'menuurl': '/', 'buttoncontrol': '0', 'supmenuid': 241 }, { 'icon': '', 'id': 243, 'menulevel': 3, 'menuname': '签证订单', 'menutop': 2, 'menuurl': '/', 'buttoncontrol': '0', 'supmenuid': 241 }, { 'icon': '', 'id': 244, 'menulevel': 3, 'menuname': '出团通知书', 'menutop': 3, 'menuurl': '/', 'buttoncontrol': '0', 'supmenuid': 241 } ], 'icon': '', 'id': 241, 'menulevel': 2, 'menuname': '订单管理', 'menutop': 1, 'menuurl': '/', 'buttoncontrol': '0', 'supmenuid': 240 }, { 'childnode': [ { 'icon': '', 'id': 246, 'menulevel': 3, 'menuname': '旅游产品', 'menutop': 1, 'menuurl': '/tourproduct', 'buttoncontrol': '0', 'supmenuid': 245 }, { 'icon': '', 'id': 247, 'menulevel': 3, 'menuname': '图库', 'menutop': 2, 'menuurl': '/basepicstore', 'buttoncontrol': '0', 'supmenuid': 245 }, { 'icon': '', 'id': 248, 'menulevel': 3, 'menuname': '签证产品', 'menutop': 3, 'menuurl': '/', 'buttoncontrol': '0', 'supmenuid': 245 } ], 'icon': '', 'id': 245, 'menulevel': 2, 'menuname': '产品管理', 'menutop': 2, 'menuurl': '/', 'buttoncontrol': '0', 'supmenuid': 240 }, { 'childnode': [ { 'icon': '', 'id': 250, 'menulevel': 3, 'menuname': '旅游广告', 'menutop': 1, 'menuurl': '/', 'buttoncontrol': '0', 'supmenuid': 249 } ], 'icon': '', 'id': 249, 'menulevel': 2, 'menuname': '广告管理', 'menutop': 3, 'menuurl': '/', 'buttoncontrol': '0', 'supmenuid': 240 } ], 'icon': '', 'id': 240, 'menulevel': 1, 'menuname': '业务中心', 'menutop': 1, 'menuurl': '/', 'buttoncontrol': '0', 'supmenuid': 0 }
实际数据为上述对象的数组。
这里主要增加了buttoncontrol
和supmenuid
,方便实现按钮权限的样式判断和选中、取消操作的checkbox级联操作。
引用组件代码:
<el-tab-pane v-for="(menu, index) in themodel" :key="index" :label="menu.menuname"> <my-tree :model="menu" ref="tree" :menulist="menu" :label="index" :selectkeys="selectkeys"></my-tree> </el-tab-pane>
themodel即为权限树数组,selectkeys为选中的权限数组集合,即id集合。
mounted()实现初始化操作:禁止checkbox的冒泡时间,selectkeys的赋值操作。
其实权限树或者说菜单树的要点就在递归算法上,按钮的选中或取消,都需要执行递归操作。这里使用jquery来协助操作,简化了许多事情,应该还是数据绑定的精神没有掌握好吧。getallkeys()获取checkbox为true的权限id返回。
实际获取选中的权限菜单的数据如下图:
总结
以上所述是小编给大家介绍的vue2.0权限树组件实现代码,希望对大家有所帮助
上一篇: JS实现电商放大镜效果