业务需求:
树形组件实现二级、三级的联动,即选择某一节点时,其他节点也要同时选中。
发现的坑
虽然el-tree
提供了setCheckedKeys
方法,但假设node-key
属性里有重复值的话,这个方法并不能批量勾选所有的node-key
。因此当两个人的value
值完全相等的情况下,value
值便无法作为node-key
使用。
解决关键点
首先需要el-tree
提供的getCheckedKeys
方法来获取所有已选择的节点;
通过setCheckedKeys
和setChecked
方法来设置节点的是否选中;
需要关闭render-after-expand
属性,保证页面加载时全部渲染,才能实时操作节点的选择;
保证node-key
必须不能重复,即使是同一个节点内容;
完整代码如下:
<template>
<div>
<el-tree ref="elTree" :data="data" :render-after-expand="false" node-key="treeId" show-checkbox @check-change="checkChange" @check="check"></el-tree>
</div>
</template>
<script>
export default {
data() {
return {
data: [],
resList: [],
resData: [{
label: '一年级',
children: [{
label: '一班',
children: [{
label: '丛思萱',
value: 1,
}, {
label: '俞长逸',
value: 2,
}, {
label: '茅诗筠',
value: 3,
}, {
label: '定茹雪',
value: 4,
}, {
label: '程华池',
value: 5,
}, {
label: '释晓曼',
value: 6,
}]
}]
}, {
label: '二年级',
children: [{
label: '一班',
children: [{
label: '丛思萱',
value: 1,
}, {
label: '伏和惬',
value: 7,
}, {
label: '茅诗筠',
value: 3,
}, {
label: '么孤云',
value: 9,
}, {
label: '淦灵松',
value: 10,
}, {
label: '慕学名',
value: 11,
}]
}, {
label: '二班',
children: [{
label: '程华池',
value: 5,
}, {
label: '后静秀',
value: 12,
}, {
label: '巴问芙',
value: 13,
}, {
label: '盖亦云',
value: 14,
}, {
label: '伏和惬',
value: 7,
}]
}]
}]
};
},
mounted() {
// 设置tree数据
this.setData();
},
methods: {
// 设置tree数据
setData() {
// 加载来自接口的数据, 本例为 resData
let resData = this.resData;
const resList = []
// 给每个子节点增加treeId
let treeId = 1
resData.forEach(item => {
if (item.children && item.children.length > 0) {
item.children.forEach(item2 => {
if (item2.children && item2.children.length > 0) {
item2.children.forEach(item3 => {
// 增加treeId
item3.treeId = treeId;
treeId ++;
// 保存现有列表
resList.push(item3)
})
}
})
}
});
this.data = resData;
this.resList = resList
},
// 节点选中状态发生变化时的回调
checkChange(data, state) {
// 获取已选择的节点
const isSelect = this.$refs.elTree.getCheckedKeys().filter(item => item);
const treeIds = []; // 用于设置要选中的节点
if (state) {
// 遍历已选择的节点
isSelect.forEach(item => {
treeIds.push(item);
// 通过现有列表查询相同节点
this.resList.forEach(item2 => {
// 获取已选择的节点对应的对象
if (item === item2.treeId) {
// 根据对象的value值再查询相同的人, 获取对应的treeId
this.resList.forEach(item3 => {
if (item2.value === item3.value && item3.treeId !== item) {
treeIds.push(item3.treeId)
}
});
}
});
});
// 统一设置选中的节点
this.$refs.elTree.setCheckedKeys(treeIds);
} else {
// 单节点判断 - 因为这里如果更改了节点选中状态时会反复触发checkChange方法,因此这里只做单体判断即可
if (data.value) {
this.resList.forEach(item => {
if (item.value === data.value) {
// 设置为不选中
this.$refs.elTree.setChecked(item.treeId, false);
}
})
}
}
},
// 当复选框被点击的时候触发 - 获取最终数据
check(data, select) {
const isSelect = select.checkedKeys.filter(item => item);
let selected = []
isSelect.forEach(item => {
if (item) {
this.resList.forEach(item2 => {
if (item === item2.treeId) {
selected.push(item2)
}
})
}
});
// 去重
const unmap = new Map()
selected = selected.filter((item) => {
return !unmap.has(item['value']) && unmap.set(item['value'], 1)
});
console.log('当前选择的最终数据:', selected);
}
}
}
</script>