最近项目中有一个需求如下:
后端返回一个树形结构的数据.返回的数据中已有设置diasbled的属性
1.任意一级别的父节点选中,其下所有的子节点都需要设置disabled属性为true.且原父节点下已有选中的子节点,需要将已选中的子节点设置成不选中
2.任意一级别的父节点取消选中,其下所有的子节点都需要将disabled属性设置成false,但是需要排除掉接口返回数据中已经是disabled数据
3.后端中返回数据中已有disabled:true属性的,不管其任意父级节点选中与否,都不会影响到他!
代码如下:
1. 后端返回的数据:
data() {
return {
realyData: [
{
id: 1,
parentId: 0,
label: "一级 2",
isLock: false,
disabled: false,
children: [
{
id: 3,
parentId: 1,
label: "二级 2-1",
isLock: false,
disabled: false,
children: [
{
id: 4,
parentId: 3,
label: "三级 3-1-1",
isLocked: false,
disabled: false,
},
{
id: 5,
parentId: 3,
label: "三级 3-1-2",
isLock: true,
disabled: true,
},
],
},
{
id: 2,
parentId: 1,
label: "二级 2-2",
isLock: false,
disabled: false,
children: [
{
id: 6,
parentId: 2,
label: "三级 3-2-1",
isLock: false,
disabled: false,
},
{
id: 7,
parentId: 2,
label: "三级 3-2-2",
isLock: false,
disabled: false,
},
],
},
],
},
],
defaultProps: {
children: "children",
label: "label",
},
};
},
2.el-tree绑定的数据
<el-tree
:data="realyData"
ref="opentree"
show-checkbox // 显示多选框
node-key="id" // 唯一标识
default-expand-all // 默认展开全部
check-strictly // 父子不互相关联
@check="check" // 当复选框被点击的时候触发
>
</el-tree>
3.数据的处理
methods: {
// check方法查阅饿了么的文档 一共俩参数
check(data, allObj) {
// 拿到当前已经选中的id
const { checkedKeys } = allObj;
// 当前点击节点是否被选中
let ischecked = checkedKeys.includes(data.id);
// 将其所有子节点已经勾选的 重置为 未勾选状态
this.resetCheckEn(ischecked, data.children);
// 设置disabled --> 这里传递进去的参数是整个el-tree绑定的data
this.findNodeFn(data.id, ischecked, this.realyData);
// 拿到所有节点的key值数组
const checkedArr = this.$refs.opentree.getCheckedKeys();
// 名称显示
const nodes = this.$refs.opentree.getCheckedNodes();
},
// 点击父节点--置空已选的下级子节点
resetCheckEn(isChecked, arr) {
if (Array.isArray(arr)) {
arr.forEach((item) => {
/**
* isLock的值与原后端返回的disabled的值相同,如果后端没有返回,可以自己递归添加上去
* isLock用来标识后端返回的原始数据是否又已经禁止操作的
* isLock == true 原始数据已经禁止任何操作的 反之 原来数据可以做操作的
* */
// 所以需要拿到原来没有禁止的数据
if (!item.isLock) {
if (isChecked) {
// isChecked === true => 父级已经勾选中了
// 所以这里需要给自己设置成不选中
this.$refs.opentree.setChecked(item.id, !isChecked);
} else {
// 父节点没有勾选 => 也需要给子节点设置成不选中
this.$refs.opentree.setChecked(item.id, isChecked);
}
}
// 递归 => 给当前点击节点的所有子节点设置成不勾选状态
if (item.children) {
this.resetCheckEn(isChecked, item.children);
}
});
}
},
/**
* 寻找当前点击的数据以及判断其是否有子节点
* faId=> 父节点的id
* faIsCheck => 父节点是否被选中
* arr => 当前el-tree绑定的数据源
* */
findNodeFn(faId, faIsCheck, arr) {
if (Array.isArray(arr)) {
arr.forEach((el) => {
// 遍历当前treeData 拿到与当前点击的id的数据
if (el.id == faId) {
// 找到当前点击的数据,将其子节点设置disable属性
this.setDisabledFn(el.children, faIsCheck, faId);
} else {
// 如果不是一级数据,递归往下找其子级(二级,三级,....)的数据,直到找到当前的数据
if (el.children) {
this.findNodeFn(faId, faIsCheck, el.children);
}
}
});
}
},
// 点击父节点--给下级所有的子节点是否设置disabled
/**
* arr --> 当前点击的父节点下的children属性数据(子节点的数据)
* faIsCheck --> 父节点是否被选中
* */
setDisabledFn(arr, faIsCheck) {
if (Array.isArray(arr)) {
arr.forEach((el) => {
// 父节点被勾选 子节点disable的属性设置为true
if (faIsCheck) {
el.disabled = true;
} else {
/**
* 父节点取消勾选的,需要排除原来就禁止操作的数据
* 将非禁止的子节点数据disable的属性设置为false
*/
if (!el.isLock) {
el.disabled = false;
}
}
// 如果子节点下还有子节点的:
//递归调用自己,直到将所有子级数据的disable属性都设置完成
if (el.children) {
this.setDisabledFn(el.children, faIsCheck);
}
});
}
},
},