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

项目使用的饿了么的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权限树组件实现代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!

以上是 Vue2.0权限树组件实现代码 的全部内容, 来源链接: utcz.com/z/333500.html

回到顶部