需求描述:
大家都知道el-tree可以很明显的通过选中来体现上下节点的父子选中状态,那么如果要求把后端把el-tree的数据结构,通过一个展开的list返回给你,使用el-checkbox组件渲染每一个节点,同时要求选中某一个节点,同时可以选中其父节点和子节点;取消也是一样。
思路:
首先el-checkbox是没有el-tree的check-strictly来严格遵循父子相关联的属性,那么想实现就需要
-
向下递归查询点击节点的子节点。
-
向上递归查询点击节点的父节点。
-
通过
indeterminate
属性用以表示 checkbox 的不确定状态,用来表示父节点的选中效果
实现效果:
使用el-checkbox实现el-tree父子关系选中效果
代码实现:
html部分:
html
<template>
<div>
<el-checkbox
v-for="(item, key) in labelList"
:label="item.labelName"
:key="key"
v-model="item.checked"
:indeterminate="item.isIndeterminate"
@change="changeCheck(item)"
></el-checkbox>
</div>
</template>
JavaScript部分:
javascript
<script>
export default {
data() {
return {
listQuery: {
labelValue: [],
},
labelList: [
// {
// labelName: '根目录',
// id: 1,
// parentId: -1,
// checked: false
// },
{
labelName: '一级 1',
id: 2,
parentId: 1,
checked: false,
},
{
labelName: '一级 2',
id: 3,
parentId: 1,
checked: false,
},
{
labelName: '一级 3',
id: 4,
parentId: 1,
checked: false,
},
{
labelName: '二级 1-1',
id: 5,
parentId: 2,
checked: false,
},
{
labelName: '三级 1-1-1',
id: 9,
parentId: 5,
checked: false,
},
{
labelName: '三级 1-1-2',
id: 10,
parentId: 5,
checked: false,
},
{
labelName: '二级 2-1',
id: 6,
parentId: 3,
checked: false,
},
{
labelName: '二级 2-2',
id: 7,
parentId: 3,
checked: false,
},
{
labelName: '二级 3-1',
id: 8,
parentId: 4,
checked: false,
},
{
labelName: '二级 3-2',
id: 11,
parentId: 4,
checked: false,
},
{
labelName: '三级 3-2-1',
id: 12,
parentId: 11,
checked: false,
},
{
labelName: '三级 3-2-2',
id: 13,
parentId: 11,
checked: false,
},
{
labelName: '三级 3-2-3',
id: 14,
parentId: 11,
checked: false,
}
]
}
},
methods: {
changeCheck(row) {
// 向下选中子级
this.downRecursiveChildren(row)
// 每次添加前先清空选中的标签的name数组
this.listQuery.labelValue = []
this.labelList.map((i) => {
if (i.checked) {
this.listQuery.labelValue.push(i.labelName)
}
})
console.log('a', this.listQuery.labelValue)
},
downRecursiveChildren(row, isGrandChildren = false) {
if (row.isIndeterminate) {
row.isIndeterminate = false
}
this.labelList.forEach((item) => {
// 判断点击的标签下,是否有子标签,如果有状态设置为true
if (row.id === item.parentId) {
item.checked = row.checked
// 判断点击的标签下的子标签是否还有子级,如果有,递归调用,把所有子级全部选中
if (this.labelList.some((v) => item.id === v.parentId)) {
this.downRecursiveChildren(item, true)
}
}
})
// 如果没有了,return
if (isGrandChildren) return
this.upRecursiveParent(row)
},
// 向上寻找父级,添加状态
upRecursiveParent(row) {
// 获取点击标签的父标签
let parentNode = this.labelList.find((v) => v.id == row.parentId)
// 定义点击标签的兄弟数组
let subing_list = []
this.labelList.forEach((item) => {
// 判断点击标签是否有相同的父级,如果有把所有的兄弟标签获取到
if (item.parentId === row.parentId) {
subing_list.push(item)
console.log('2', subing_list)
}
})
if (parentNode) {
// 所有的兄弟节点全部选中且没有不确定状态, 需要选中父标签节点
if (
subing_list.every((item) => item.checked && !item.isIndeterminate)
) {
// 全选中且没有不确定状态
parentNode.checked = true
parentNode.isIndeterminate = false
console.log('3')
} else if (
// 所有的兄弟节点全部选中且没有不确定状态, 需要选中父标签节点
subing_list.every((item) => !item.checked && !item.isIndeterminate)
) {
// 全不选中并且没有不确定状态,不需要选中父标签节点
parentNode.checked = false
parentNode.isIndeterminate = false
console.log('4')
} else {
// 有部分选中,父节点需要设置为半选状态
parentNode.checked = false
parentNode.isIndeterminate = true
console.log('5', parentNode)
}
if (parentNode.parentId !== 1) {
this.upRecursiveParent(parentNode)
}
}
}
},
}
</script>