一、代码结构
有一天小编在改一个 el-tree 的问题,代码是类似下方的结构:
<template>
<div>
<el-tree
:data="treeData"
show-checkbox
node-key="id"
ref="tree"
@check-change="handleCheckChange"
></el-tree>
</div>
</template>
<script>
export default {
data() {
return {
treeData: [
{
id: 1,
label: '一级 1',
sts: 0, // 初始状态为0
children: [
{
id: 4,
label: '二级 1-1',
sts: 0, // 初始状态为0
},
],
},
{
id: 2,
label: '一级 2',
sts: 0, // 初始状态为0
children: [
{
id: 5,
label: '二级 2-1',
sts: 0, // 初始状态为0
children: [
{
id: 6,
label: '三级 2-1-1',
sts: 0, // 初始状态为0
},
],
},
],
},
{
id: 3,
label: '一级 3',
sts: 0, // 初始状态为0
children: [
{
id: 7,
label: '二级 3-1',
sts: 0, // 初始状态为0
},
{
id: 8,
label: '二级 3-2',
sts: 0, // 初始状态为0
},
],
},
],
};
},
methods: {
handleCheckChange(data, checked, indeterminate) {
this.updateNodeStatus(data, checked);
},
updateNodeStatus(node, checked) {
node.sts = checked ? 1 : 0;
if (node.children) {
node.children.forEach(child => {
this.updateNodeStatus(child, checked);
});
}
},
},
};
</script>
二、定位问题
经定位,发现在使用 check-change 方法监听的时候,假如当前节点的树都未选中,取消选中其中的某一个子节点,如下图:
此时,check-change函数会被触发三次:(1)子节点自己改变(2)子节点的父节点有所改变(3)子节点的祖父节点也有所改变;所以此时 updateNodeStatus 函数会被调用三次,并且将当前节点下的child都回置父节点的选中状态,从而导致“一级1”整个节点都未选中。
思路1、check-strictly
该功能是:在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false,设置为true的话,父子节点完全不会联动,显然不是小编想要的效果;
最终解决办法:
1、在用户操作树的时候不做任何修改数据的操作;
2、在用户点击保存按钮时,通过 getCheckedKeys 方法获取所有当前选中的节点id数组;然后通过递归遍历 treeData 原数组,将包含在 getCheckedKeys 数组中的节点sts字段置为相对应的状态即可。
<template>
<div>
<el-tree
:data="treeData"
show-checkbox
node-key="id"
ref="tree"
></el-tree>
</div>
</template>
<script>
export default {
data() {
return {
treeData: [
{
id: 1,
label: '一级 1',
sts: 0, // 初始状态为0
children: [
{
id: 4,
label: '二级 1-1',
sts: 0, // 初始状态为0
},
],
},
{
id: 2,
label: '一级 2',
sts: 0, // 初始状态为0
children: [
{
id: 5,
label: '二级 2-1',
sts: 0, // 初始状态为0
children: [
{
id: 6,
label: '三级 2-1-1',
sts: 0, // 初始状态为0
},
],
},
],
},
{
id: 3,
label: '一级 3',
sts: 0, // 初始状态为0
children: [
{
id: 7,
label: '二级 3-1',
sts: 0, // 初始状态为0
},
{
id: 8,
label: '二级 3-2',
sts: 0, // 初始状态为0
},
],
},
],
};
},
methods: {
handleCheckChange(data, checked, indeterminate) {
this.updateNodeStatus(data, checked);
},
updateNodeStatus(node, checked) {
node.sts = checked ? 1 : 0;
if (node.children) {
node.children.forEach(child => {
this.updateNodeStatus(child, checked);
});
}
},
updateSts(tree,chooseIds) {
tree.forEach(node => {
const isChosen = chooseIds.includes(node.id)
node.sts = isChosen ? 1 : 0;
if(node.children) {
this.updateSts(node.children,chooseIds)
}
})
},
getTreeData() {
let chooseIds = this.$refs.tree.getCheckedKeys();
this.updateSts(this.treeData,chooseIds);
console.log(this.treeData)
}
},
};
</script>