【问题标题】:How to add a child node in a nested object at a particular position using javascript如何使用javascript在特定位置的嵌套对象中添加子节点
【发布时间】:2026-02-14 12:10:02
【问题描述】:

我有一个如下所示的数据结构

ds: [
          { id: "0a12", pos: 0, name: "PH1" },
          {
            id: "8f83",
            name: "PH2",
            pos: 1,
            children: [
              { id: "ll54", pos: 0, name: "L1" },
              {
                id: "97cs",
                name: "L2",
                pos: 1,
                children: [
                  { id: "80s3", pos: 0, name: "LL1" },
                  { id: "2dh3", pos: 1, name: "LL2" },
                ],
              },
            ],
          },
          { id: "75fd", pos: 2, name: "PH3" },
          { id: "34jg", pos: 3, name: "PH4" },
        ],

我正在创建一个组织结构图,其中我可以选择在左侧或右侧添加一个节点。 单击节点时,如果单击“LL1”,我可以获得节点 obj 作为参数(即),我可以获得该对象,以及称为类型的第二个参数,它将包含“左”或“右”。

所以现在 type == 'left' 那么我的结果数据结构应该是这样的

ds: [
          { id: "0a12", pos: 0, name: "PH1" },
          {
            id: "8f83",
            name: "PH2",
            pos: 1,
            children: [
              { id: "4", pos: 0, name: "L1" },
              {
                id: "5",
                name: "L2",
                pos: 1,
                children: [
                  { id: "36fd", pos: 0, name: "" }, // new node for type === 'left'
                  { id: "80s3", pos: 1, name: "LL1" },
                  { id: "2dh3", pos: 2, name: "LL2" },
                ],
              },
            ],
          },
          { id: "75fd", pos: 2, name: "PH3" },
          { id: "34jg", pos: 3, name: "PH4" },
        ],

如果类型 === 'right'

ds: [
          { id: "0a12", pos: 0, name: "PH1" },
          {
            id: "8f83",
            name: "PH2",
            pos: 1,
            children: [
              { id: "4", pos: 0, name: "L1" },
              {
                id: "5",
                name: "L2",
                pos: 1,
                children: [
                  { id: "80s3", pos: 0, name: "LL1" },
                  { id: "36fd", pos: 1, name: "" }, // new node for type === 'right'
                  { id: "2dh3", pos: 2, name: "LL2" },
                ],
              },
            ],
          },
          { id: "75fd", pos: 2, name: "PH3" },
          { id: "34jg", pos: 3, name: "PH4" },
        ],

注意:对于那些没有子节点的节点,我们不应该将空数组初始化为 children 属性

【问题讨论】:

    标签: javascript arrays vue.js vuejs2 nested


    【解决方案1】:

    您可以使用Array.slicespread operator 将新节点插入到您的数组中。

    let data = [
      { id: '0a12', pos: 0, name: 'PH1' },
      {
        id: "8f83",
        name: "PH2",
        pos: 1,
        children: [
          { id: '4', pos: 0, name: 'L1' },
          {
            id: '5',
            name: 'L2',
            pos: 1,
            children: [
               { id: '80s3', pos: 0, name: 'LL1' },
               { id: '2dh3', pos: 1, name: 'LL2' },
            ],
          },
       ],
      },
      { id: '75fd', pos: 2, name: 'PH3' },
      { id: '34jg', pos: 3, name: 'PH4' },
    ];
    
    function addNode(direction, idElement, ptr) {
      const elementIndex = ptr.findIndex(x => x.id === idElement);
    
      if (elementIndex === -1) {
        // Go deeper
        return ptr.map(x => x.children ? {
           ...x,
           children: addNode(direction, idElement, x.children),
        }: x);
      }
      
      const offset = direction === 'left' ? 0 : 1;
      
      // Insert the new node in the correct position
      const mutatedPtr = [
         ...ptr.slice(0, elementIndex + offset),
          
         { id: 'XXXX', pos: elementIndex + offset, name: '' },
          
         ...ptr.slice(elementIndex + offset),
      ];
      
      // change the positions
      mutatedPtr.forEach((x, xi) => {
        x.pos = xi;
      });
      
      return mutatedPtr;
    }
    
    data = addNode('right', '75fd', data);
    data = addNode('left', '75fd', data);
    data = addNode('left', '2dh3', data);
    data = addNode('right', '2dh3', data);
    
    console.log(data);

    【讨论】:

    • 这将在第一级工作,但如果我单击“LL1”并想在其左侧或右侧插入一个节点怎么办?
    • 我已经通过将函数递归进行了更改 :) 现在它甚至会更改嵌套节点
    • 无论哪种情况,它的插入节点都只在右边而不在左边
    • 好像左右都可以,还是我误解了左右是什么?
    • 天哪,对不起...我没有替换硬编码值..我的错误
    【解决方案2】:

    这是一个树插入问题。首先,您需要找到锚节点的索引,然后如果 type 为“left”,则在 index 处插入一个新节点,如果 type 为“right”,则在 index + 1 处插入一个新节点。这是适用于您的情况的解决方案。请注意,您需要使用您拥有的任何 id 生成器设置正确的“id”。

    ds = [
      { id: "0a12", pos: 0, name: "PH1" },
      {
        id: "8f83",
        name: "PH2",
        pos: 1,
        children: [
          { id: "4", pos: 0, name: "L1" },
          {
            id: "5",
            name: "L2",
            pos: 1,
            children: [
              { id: "80s3", pos: 0, name: "LL1" },
              { id: "2dh3", pos: 1, name: "LL2" }
            ]
          }
        ]
      },
      { id: "75fd", pos: 2, name: "PH3" },
      { id: "34jg", pos: 3, name: "PH4" }
    ];
    
    // Returns parent & position
    function findNode(childNodes, name) {
      for (var ii = 0; ii < childNodes.length; ii++) {
        let child = childNodes[ii];
        if (child.name == name) {
          return {
            childNodes: childNodes,
            index: ii
          };
        }
        if (child.children) {
          let result = findNode(child.children, name);
          if (result) {
            return result;
          }
        }
      }
      return null;
    }
    
    function rewritePositions(childNodes) {
      for (var ii = 0; ii < childNodes.length; ii++) {
        childNodes[ii].pos = ii;
      }
    }
    
    function insertNode(name, type) {
      let searchResult = findNode(ds, name);
      if (!searchResult) {
        return;
      }
    
      let index = searchResult.index;
      let newPosition = type === "left" ? index : index + 1;
      let newNode = { id: "todo: index", pos: newPosition, name: "" };
      searchResult.childNodes.splice(newPosition, 0, newNode);
      rewritePositions(searchResult.childNodes);
    }
    

    【讨论】:

    • 说如果单击的节点位置为 0,并且我想在其左侧插入一个节点,那么按照您的逻辑,目标索引将为 -1,那么上面的代码在这种情况下仍然有效吗?
    • 不错的收获。当 type == left 时,索引实际上不应该改变。解决了这个问题。