基于elementuicheckbox 树形多级联动
背景
公司业务有个⾓⾊权限设置的需求,数据可能有5到6层的权限,本来是想直接使⽤的组件的,奈何难以修改,要做成公司想要的样⼦,只好⾃⼰写了。数据结构后台返回的数据结构是这样的:
接⼝权限数据
后台会返回⼀个数组,每个数组对象对应⼀个菜单,权限数据都在数组⾥。权限选择的⼤概的样⼦:拆分组件
⽗组件引⼊封装好的组件,将需要的数据传⼊。
编辑回显时,调⽤⼦组件的⽅法
初次拿到数据时,将后台返回的数据重新设置⼀下,给予初始的选中以及半选状态保存权限时,拿到所有已选择权限的组件部分,写第⼀级的权限点击任何,都会进⼊到⽅法,再通过和⽅法不断递归设置整个数据的选中以及半选状态,代码如下:
elementui el-tree ui menuTreeList ui checkboxTree <checkboxTree ref="checkTreeRef" :role-list="tableData"></checkboxTree>
this.$furbishTreeCheckStatus(res.data, this.tableData)
this.tableData = this.$refs.checkTreeRef.formatTreeData(res.data)
roleId
checkboxTree html <template>
<div>
<template v-for="item in roleList">
<template v-for="treeData uTreeList">
<div :key="treeData.id">
<p class="check-group">
<el-checkbox v-model="hecked" :indeterminate="treeData.isIndeterminate" @change="handleCheckAllChange({ val: treeData, checked: $event })"> {{ treeData.name }}
</el-checkbox>
</p>
<checkboxTreeRender :tree-data="treeData" @handle-check-all-change="handleCheckAllChange"></checkboxTreeRender>
</div>
</template>
</template>
</div>
</template>
checkbox handleCheckAllChange findChildren findParent handleCheckAllChange(data) { let
{ val, checked } = data
if (val.children.length > 0) {
// 处理下级
this.findChildren(val.children, checked)
} el {
// 处理本级
val.children.forEach((v) => {
})
}
if (val.parentId !== -1) {
/
/ 处理上级
this.leList, val.parentId)
}
val.isIndeterminate = fal
},
// 设置⼦级
findChildren(list, checked) {
list.forEach((child) => {
child.isIndeterminate = fal
if (child.children.length > 0) {
this.findChildren(child.children, checked)
}
})
蛇和鼠合不合>孙悟空怎么玩},
// 设置这⼀整条线
findParent(list, parentId) {
list.forEach((k) => {
if (k.menuTreeList) {
this.handleList(child, parentId)
这是主要选择交互的联动逻辑,下⾯是⼀些⼯具⽅法,主要是⽤于业务保存时需要传递权限,以及初
始拿到后台数据时需要⼀下,代码如下:最后,编辑⾓⾊时需要回显⾓⾊权限,后台返回给我的数据结构和全部权限是⼀致的,只是只会返回已经选择的权限数据,当然,对我来说,什么结构都⽆所谓,因为我这种做法,实际上是要递归把所有权限丢到⼀个数组⾥⾯,
我的思路是先拿到所有的权限数组放到⾥,然后将所有权限在⾥的对象设置为已选,再重新去设置半选,当前对象是已选,但对象的已选⽐的长度少,说明当前对象是半选。代码如下:
this.handleList(child, parentId) })
} el {
this.handleList(k, parentId)
} })
}, // 设置这⼀整条线具体⽅法
handleList(child, parentId) {
let parentCheckedLength = 0
let parentIndeterminateLength = 0
if (child.id === parentId) {
child.children.forEach((children) => {
if (children.isIndeterminate) {
parentIndeterminateLength++
} el if (hecked) {
parentCheckedLength++
特殊反义词}
})
child.isIndeterminate = (parentIndeterminateLength > 0 || parentCheckedLength > 0) && parentCheckedLength < child.children.length
if (child.parentId !== -1) {
this.leList, child.parentId)
}
} el if (child.children.length > 0) {
this.findParent(child.children, parentId)
}
},
checkbox id format const returnCheckTree = (data, checkArr = []) => {
data.forEach((v) => {
if (v.mychecked || v.isIndeterminate) {
!checkArr.includes(v.id) && checkArr.push(v.id)
}
if (v.children && v.children.length) {
returnCheckTree(v.children, checkArr)
抗日战争故事
}
})
return checkArr
}
const fmtTreeData = (data) => {
data.forEach((v) => {
v.isIndeterminate = fal
if (v.children && v.children.length > 0) {
fmtTreeData(v.children)
}
荷花的诗句})
return data
}
// 返回所有已选或权限的role
returnAllCheckIds(currentData) {
let roleIds = []
currentData.forEach((k) => {
roleIds = [...uTreeList), ...roleIds]
大小比
})
return roleIds.join(',')
},
// 初始化树状数据
formatTreeData(currentData) {
currentData.forEach((k) => {
uTreeList)
})
return currentData
},
id id roleIds id roleIds children children const returnEditRoleTreeIds = (data, checkArr = []) => {
data.forEach((v) => {
!checkArr.includes(v.id) && checkArr.push(v.id)
if (v.children && v.children.length) {
returnEditRoleTreeIds(v.children, checkArr)
}
})
return checkArr
}
应该不是最好的思路,各位有更好的建议可以在评论区告诉我。组件这个组件主要是递归组件,去渲染树形结构。
接收⼀个数据对象以及将变化的⽅法抛给⽗组件去处理,这个组件只负责渲染
}
// 编辑时回显权限数据
refurbishTreeCheckStatus(checkData, allData) {
let roleIds = []
let firstLevelIds = []
let notFirstLevelIds = []
checkData.forEach((k) => {
roleIds = [...uTreeList), ...roleIds]
})
allData.forEach((k) => {
this.uTreeList, roleIds)
})
allData.forEach((k) => {
this.uTreeList)
})
},
// 所有已选择的role 全部设置为已选
tTreeCheckStatus(data, roleIds = []) {
data.forEach((v) => {
if (roleIds.includes(v.id)) {
}
if (v.children && v.children.length) {
this.tTreeCheckStatus(v.children, roleIds)
}
})
},
// 重新递归设置半选状态
tTreeIndeterminateStatus(data) {
data.forEach((v) => {
let parentCheckedLength = 0
let parentIndeterminateLength = 0
v.children.forEach((children) => {
if (children.isIndeterminate) {
parentIndeterminateLength++
} el if (hecked) {
parentCheckedLength++
}
})
七根火柴v.isIndeterminate = (parentIndeterminateLength > 0 || parentCheckedLength > 0) && parentCheckedLength < v.children.length
if (v.children && v.children.length) {
this.tTreeIndeterminateStatus(v.children)
}
})
},
checkboxTreeRender dom <template>
<div>
<div v-if="treeData.children && treeData.children.length" >
<div v-for="childrenData in treeData.children" :key="childrenData.id" :>
<el-checkbox
v-model="hecked"
:indeterminate="childrenData.isIndeterminate"
:label="childrenData.id"
教师资格证报名时间@change="handleCheckAllChange({ val: childrenData, checked: $event })"
>
{{ childrenData.name }}
</el-checkbox>
<checkboxTreeRender :tree-data="childrenData" @handle-check-all-change="handleCheckAllChange"></checkboxTreeRender>
</div>
</div>
</div>
</template>
props: {
treeData: {
type: Object,
default: function () {
return {}
},
},
},
checkbox returnStyle(child) {
⾄此,⼀个基于的多层树形联动组件就写好了。结语
最开始需求是说最多只有三层结构,所以我就写了⼀版写死的三层联动的逻辑,使⽤了,只需要在上进⾏监听就能拿到下⾯所有选择的。后⾯说要⽀持更多层,发现当初这样⼦已经⽆法实现,当初写的太呆了,
于是重新写了⼀版,通过这次对递归的使⽤也有了⼀些理解,因为以前很少使⽤这个,也算是学习到了,记录⼀下。
全部源码放到上了, returnStyle(child) {
const premi = child && child.length
return {
display: premi ? '' : 'inline-block',
marginRight: premi ? '' : '30px',
}
},
handleCheckAllChange(data) {
this.$emit('handle-check-all-change', data)
},
elementui checkbox checkboxGroup checkboxGroup checkbox github