在项目中遇到一个难点,纠结了一整天,凌晨算是把这个算法给折腾出来了,用比较笨的方法实现的,如果有更好的方法,欢迎各位大佬纠正。
场景是这样的:公司的部门数据是个树形数据,而我从后端拿到的启用的部门只是一个数组id,因此要把树形数据里的对应id元素下的disabled放开。同时该节点下还有子节点的,也要把子节点设置为可用。
遍历修改树形数据都知道用递归,然而这次传入的不是单一的id,而是一个id数组,如果单纯遍历id再遍历数组就会将已经修改的元素又改回去,同时要修改的还不止当前节点,子节点也要一并修改。所以场景比较复杂。
我的实现思路是:先遍历id数组,在id数组下调用递归函数,递归函数需要传入3个参数,参数1是部门数据,参数2是当前的id,最关键的是参数3,是当前节点的上一节父节点,查找上一节父节点,我在网上找了个方法并修改了一下,只让它返回当前节点的上一个父节点。
// 树形数据
let arr = [
{
id: 1,
label: '1',
dis: true,
children: [
{
id: 11,
label: '1.1',
dis: true,
children: [
{
id: 111,
label: '1.1.1',
dis: true,
children: [
{
id: 1111,
label: '1.1.1.1',
dis: true,
},
{
id: 1112,
label: '1.1.1.2',
dis: true,
},
]
},
{
id: 112,
label: '1.1.2',
dis: true,
},
]
},
{
id: 12,
label: '1.2',
dis: true,
children: [
{
id: 121,
label: '1.2.1',
dis: true,
},
{
id: 122,
label: '1.2.2',
dis: true,
},
]
}
]
}
]
// 要修改的id值数组
let list = [111, 121]
const fn1 = (arr, list) => {
// 上级父节点查询函数
function findParentArr(targetId) {
const ids = []
function getParent(sources) {
if (Array.isArray(sources)) {
return sources.find(elm => {
let rs = getParent(elm)
if (rs) {
ids.push(elm)
}
return rs
})
}
if (sources.id === targetId) {
return true
}
if (Array.isArray(sources.children)) {
return getParent(sources.children)
}
}
getParent(arr)
if (ids.length === 1) return ids[0];
else return ids[1]
}
const fn = (arr, id, pNode) => {
arr.forEach((item) => {
// 每次递归进来都给他传入一个父节点
pNode = findParentArr(item.id)
// 三个判断条件, id是否相等,当前dis是否已经为false,防止修改已经修改的节点,上一级父节点
// 父节点ids为false,直接让该节点设置成false;父节点不满足则检测其他两个条件是否满足
if (item.id === id || !item.dis || pNode) {
if (!pNode.dis) {
item.dis = false
} else {
item.dis = !(item.id === id || !item.dis)
}
}
if (item.children && item.children.length > 0) {
fn(item.children, id, pNode)
}
})
}
list.forEach((id) => {
// 初始父节点为Null,从头节点开始
fn(arr, id, null)
})
}
fn1(arr, list)
console.log(arr);