Vue2.0权限树组件实现代码


Posted in Javascript onAugust 29, 2017

项目使用的饿了么的Element-Ui,权限树使用其树形控件:

<el-tree :data="data" ></el-tree>

Vue2.0权限树组件实现代码

刚开始没有特殊需求,三级分支,效果看着还可以。但是接下来的新需求:增加页面操作按钮权限,即达到四级分支,同时要求四级权限布局方式为横向,而且操作按钮权限非固定四级树,但是样式要求一致。这样子就很难操作了,如果单单是四级树为横向,还可以调调样式完成。本来想修改element的tree控件源码来实现,网上查了一些资料,还没有很好的办法生成其编译文件。最终决定自己写组件完成上述需求。

先上效果图:

Vue2.0权限树组件实现代码

基本可以满足需求,样式稍微比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 
 }

实际数据为上述对象的数组。

这里主要增加了buttonControlsupMenuId,方便实现按钮权限的样式判断和选中、取消操作的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权限树组件实现代码

总结

以上所述是小编给大家介绍的Vue2.0权限树组件实现代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
最常用的12种设计模式小结
Aug 09 Javascript
利用js判断浏览器类型(是否为IE,Firefox,Opera浏览器)
Nov 22 Javascript
jQuery的3种请求方式$.post,$.get,$.getJSON
Mar 28 Javascript
jQuery实现限制textarea文本框输入字符数量的方法
May 28 Javascript
JS+CSS实现自适应选项卡宽度的圆角滑动门效果
Sep 15 Javascript
理解JS事件循环
Jan 07 Javascript
leaflet的开发入门教程
Nov 17 Javascript
JS实现touch 点击滑动轮播实例代码
Jan 19 Javascript
jQuery实现获取h1-h6标题元素值的方法
Mar 06 Javascript
JavaScript递归算法生成树形菜单
Aug 15 Javascript
微信小程序实现动态改变view标签宽度和高度的方法【附demo源码下载】
Dec 05 Javascript
react中使用swiper的具体方法
May 15 Javascript
基于Vue实现后台系统权限控制的示例代码
Aug 29 #Javascript
jQuery动态添加.active 实现导航效果代码思路详解
Aug 29 #jQuery
laravel5.4+vue+element简单搭建的示例代码
Aug 29 #Javascript
详解从新建vue项目到引入组件Element的方法
Aug 29 #Javascript
jQuery实现base64前台加密解密功能详解
Aug 29 #jQuery
浅谈vuex之mutation和action的基本使用
Aug 29 #Javascript
vuex学习之Actions的用法详解
Aug 29 #Javascript
You might like
使用php判断浏览器的类型和语言的函数代码
2013/02/28 PHP
浅析虚拟主机服务器php fsockopen函数被禁用的解决办法
2013/08/07 PHP
php json与xml序列化/反序列化
2013/10/28 PHP
Laravel框架下载,安装及路由操作图文详解
2019/12/04 PHP
会自动逐行上升的文本框
2006/06/30 Javascript
Web开发之JavaScript
2012/03/29 Javascript
javascript函数定义的几种区别小结
2014/01/06 Javascript
jquery缓动swing liner控制动画过程不同时刻的速度
2014/05/29 Javascript
Js实现手机发送验证码时按钮延迟操作
2014/06/20 Javascript
jquery隔行换色效果实现方法
2015/01/15 Javascript
jQuery功能函数详解
2015/02/01 Javascript
js验证框架之RealyEasy验证详解
2016/06/08 Javascript
jquery 仿锚点跳转到页面指定位置的实例
2017/02/14 Javascript
JS实现向iframe中表单传值的方法
2017/03/24 Javascript
js字符串与Unicode编码互相转换
2017/05/17 Javascript
Vue.js中的图片引用路径的方式
2017/07/28 Javascript
JavaScript实现简单动态进度条效果
2018/04/06 Javascript
JavaScript获取页面元素的常用方法详解
2019/09/28 Javascript
JS几个常用的函数和对象定义与用法示例
2020/01/15 Javascript
python基于Tkinter库实现简单文本编辑器实例
2015/05/05 Python
详解Python中的strftime()方法的使用
2015/05/22 Python
Django中更新多个对象数据与删除对象的方法
2015/07/17 Python
Python的Twisted框架中使用Deferred对象来管理回调函数
2016/05/25 Python
Python中datetime模块参考手册
2017/01/13 Python
简单了解python变量的作用域
2019/07/30 Python
python学生信息管理系统实现代码
2019/12/17 Python
Python Dict找出value大于某值或key大于某值的所有项方式
2020/06/05 Python
Python接收手机短信的代码整理
2020/08/02 Python
使用CSS3的font-face字体嵌入样式的方法讲解
2016/05/13 HTML / CSS
美国网上书店:Barnes & Noble
2018/08/15 全球购物
IdealFit官方网站:女性蛋白质、补充剂和运动服装
2019/03/24 全球购物
杭州SQL浙江浙大网新恩普软件有限公司
2013/07/27 面试题
2014年法院工作总结
2014/11/24 职场文书
关于感谢信的范文
2015/01/23 职场文书
2015年护士长个人工作总结
2015/04/24 职场文书
windows安装python超详细图文教程
2021/05/21 Python