如何解决在像数据结构这样的嵌套树中,如何通过父节点的 id 将子节点添加到父节点的子数组?
const data = {
id: 'root',name: 'Parent',children: [
{
id: '1',name: 'Child - 1',},{
id: '3',name: 'Child - 3',children: [
{
id: '4',name: 'Child - 4',],};
而且我想通过 id 将新的子数组动态添加到任何父元素。例如。我想找到 id='4' 的元素并添加子项:[{ id:'5',name: 'Child - 4' }]
解决方法
当 id
匹配时,您可以构建一个递归函数来向子数组添加数据。
const data = [{ id: 'root',name: 'Parent',children: [ { id: '1',name: 'Child - 1',},{ id: '3',name: 'Child - 3',children: [ { id: '4',name: 'Child - 4',],}];
const addDataToId=(arr,id,children)=>{
arr.forEach(i=>{
if(i.id==id){
i.children = [...(i.children || []),...children];
} else {
addDataToId(i.children|| [],children)
}
})
}
addDataToId(data,4,[{ id:'5',name: 'Child - 4' }]);
console.log(data);
正如在对 OP 问题的评论中已经建议的那样,可以选择一种递归方法,通过 Array.prototype.some
在内部迭代父节点的 children
数组,以实现早期退出(在数组迭代) 以及是否可以通过其布尔返回值添加 (a) 子节点(如果目标父节点存在)的指示。
还必须了解可能的子节点重复(通过它们的 id
)以及如何处理它们。
// E.g. I want to find element with id='4'
// and add children: [{ id:'5',name: 'Child - 4' }]
const data = {
id: 'root',children: [
{
id: '1',{
id: '3',children: [
{
id: '4',};
function addChildrenToParentByParentId(id,node,childNodes) {
let isSuccess = false;
const { children } = node;
if (node.id === id) {
// because `childNodes` can be both a single node or a node list.
childNodes = [].concat(childNodes);
// prevent child node duplicates by ...
node.children =
((Array.isArray(children) && children) || []).filter(child =>
// ... skipping older nodes which feature newer ids ...
childNodes.every(node => node.id !== child.id)
// ... and always concatenating the most recent child nodes.
).concat(childNodes);
isSuccess = true;
} else if (Array.isArray(children)) {
// recursion ... but using `Array.prototype.some`
// in order to achieve both an early exit and the
// indication whether children could be added.
isSuccess = children.some(child =>
addChildrenToParentByParentId(id,child,childNodes)
);
}
return isSuccess;
}
// fails ... provides a node list
console.log(
"addChildrenToParentByParentId('2',data,name: 'Child - 4' }]) ...",addChildrenToParentByParentId('2',name: 'Child - 4' }])
);
console.log(data);
// succeeds ... provides a single node
console.log(
"addChildrenToParentByParentId('4',{ id:'5',name: 'Child - 4' }) ...",addChildrenToParentByParentId('4',name: 'Child - 4' })
);
console.log(data);
// succeeds ... provides a node list
console.log(
"addChildrenToParentByParentId('3',[{ id:'6',name: 'Child - 4' },{ id:'7',addChildrenToParentByParentId('3',name: 'Child - 4' }])
);
console.log(data);
// succeeds ... provides a single node ... prevents duplicates
console.log(
"addChildrenToParentByParentId('3',{ id:'6',name: 'Child - XX' }) ...",name: 'Child - XX' })
);
console.log(data);
.as-console-wrapper { min-height: 100%!important; top: 0; }
我更喜欢通过将树遍历与测试是否在当前节点上工作的谓词和更新节点的转换函数分开来编写这样的函数。
这是一个带有 alterTree
函数的版本,它执行树遍历,接受谓词函数和转换函数并返回一个接受对象的函数(.children
数组保持树结构) 并通过对与谓词匹配的所有节点调用转换函数并保持其他节点不变来转换所有与谓词匹配的节点,从而返回该对象的更改版本:
const alterTree = (pred,trans) => (o) =>
pred (o)
? trans (o)
: {...o,...(o .children ? {children: o .children .map (alterTree (pred,trans))} : {})}
const addChildren = (targetId,children) =>
alterTree (
({id}) => id === targetId,(node) => ({...node,children: [... (node .children || []),... children]})
)
const data = {id: 'root',children: [{id: '1',{id: '3',children: [{id: '4',name: 'Child - 4'}]}]};
console .log (addChildren ('4',[{id: '5',name: 'Child - 5'}]) (data))
.as-console-wrapper {max-height: 100% !important; top: 0}
我们在 alterTree
的定义中调用 addChildren
,传递一个报告 id
是否与我们的目标匹配的函数和一个添加节点的第二个函数。
请注意,alterTree
的工作是不变的。但是如果你传递给它的函数改变了它们的输入,就不能保证我们不会改变你的原始对象。 addChildren
传递的那些,但是不会改变任何东西,所以这个函数也不会改变原始数据。它返回应用了更改的对象的新副本。
如果我们愿意,我们可以更进一步,抽象出 "children"
用于我们的后代节点,但这有点离题了。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。