JS 实现树形结构的各种操作(1)

一  实现单个字段的过滤

        本方法原文为:JS实现树形结构数据的模糊搜索查询

         需求描述:输入 “题2” 字,希望树形结构中带有 “题2” 字的项显示,即使父节点没有,但子节点含有,父节点仍要返回,树节点如下:

let arr = [
  {
    title: '标题1',
    children: [
      {
        title: '标题11',
        children: null
      },
      {
        title: '标题21',
        children: null
      }
    ]
  },
  {
    title: '标题2',
    children: [
      {
        title: '标题22',
        children: null
      }
    ]
  },
  {
    title: '标题3',
    children: null
  }
];

代码实现:

let mapTree = (value, arr) => {
  let newarr = [];
  arr.forEach(element => {
    if (element.title.indexOf(value) > -1) { // 判断条件
      newarr.push(element);
    } else {
      if (element.children && element.children.length > 0) {
        let redata = mapTree(value, element.children);
        if (redata && redata.length > 0) {
          let obj = {
            ...element,
            children: redata
          };
          newarr.push(obj);
        }
      }
    }
  });
  return newarr;
};

console.log(mapTree('题2', arr));

运行结果:

[
  {
    title: '标题1',
    children: [
      {
        title: '标题21',
        children: null
      }
    ]
  },
  {
    title: '标题2',
    children: [
      {
        title: '标题22',
        children: null
      }
    ]
  }
]

二 过滤多个属性

本方法同样来源于:JS实现树形结构数据的模糊搜索查询

代码实现如下:

matchTreeData(arr, searchCon) {
  let newArr = [];
  let searchNameList = ['name', 'code', 'title'];
  arr.forEach((item) => {
    for (let i = 0, len = searchNameList.length; i < len; i++) {
      let nameKey = searchNameList[i];
      if (item.hasOwnProperty(nameKey)) {
        if (item[nameKey] && item[nameKey].indexOf(searchCon) !== -1) {
          newArr.push(item);
          break;
        } else {
          if (item.childList && item.childList.length > 0) {
            let resultArr = this.matchTreeData(item.childList, searchCon);
            if (resultArr && resultArr.length > 0) {
              newArr.push({
                ...item,
                childList: resultArr
              })
              break;
            }
          }
        }
      } else {
        continue;
      }
    }
  })
  return newArr;
}

三 实现同一属性的多个字段同时过滤,并返回一个父节点

原始数据结构如下:

[
    {
        id: "1",
        name: "一级菜单1",
        children: [
            {
                id: "1-1",
                name: "二级菜单1-1",
                children: [
                    {
                        id: "1-1-1",
                        name: "三级菜单1-1-1",
                    },
                    {
                        id: "1-1-2",
                        name: "三级菜单1-1-2",
                    },
                    {
                        id: "1-1-3",
                        name: "三级菜单1-1-3",
                    }
                ]
            }
        ]
    }, {
        id: "2",
        name: "一级菜单2",
        children: [
            {
                id: "2-1",
                name: "二级菜单2-1",
            }
        ]
    }, {
        id: "3",
        name: "一级菜单3",
    }

]

需要过过滤的字段如下:

const targetMenuName = ["三级菜单1-1-1", "三级菜单1-1-3", "一级菜单3"];

目标结果如下:

[
  {
    "id": "1",
    "name": "一级菜单1",
    "children": [
      {
        "id": "1-1",
        "name": "二级菜单1-1",
        "children": [
          {
            "id": "1-1-1",
            "name": "三级菜单1-1-1"
          },
          {
            "id": "1-1-3",
            "name": "三级菜单1-1-3"
          }
        ]
      }
    ]
  },
  {
    "id": "3",
    "name": "一级菜单3"
  }
]

实现方法如下:

function filterMenu(menu, targetIds) {
    // 递归函数,用于过滤菜单项
    function filterRecursive(item, targetIds) {
        // 如果当前项的ID匹配目标IDs中的某个ID,保留该项
        if (targetIds.includes(item.name)) {
            return true;
        }

        // 如果当前项有子项,递归过滤子项
        if (item.children) {
            item.children = item.children.filter(child => filterRecursive(child, targetIds));
            // 如果子项中有匹配的,保留当前项
            if (item.children.length > 0) {
                return true;
            }
        }

        // 如果没有匹配的name,且没有子项,删除当前项
        return false;
    }

    // 初始调用
    return menu.filter(item => filterRecursive(item, targetIds));
}

四  对tree 中相同父节点的子节点进行合并到同一个父节点中展示。

原始数据如下:

const tree1 = [
    {
        id: "1",
        name: "一级菜单1",
        children: [
            {
                id: "1-1",
                name: "二级菜单1-1",
                children: [
                    {
                        id: "1-1-1",
                        name: "三级菜单1-1-1"
                    }
                ]
            }
        ]
    },
    {
        id: "2",
        name: "一级菜单2",
        children: [
            {
                id: "2-1",
                name: "二级菜单2-1"
            }
        ]
    },
    {
        id: "3",
        name: "一级菜单3"
    }
];

const tree2 = [
    {
        id: "1",
        name: "一级菜单1",
        children: [
            {
                id: "1-1",
                name: "二级菜单1-1",
                children: [
                    {
                        id: "1-1-2",
                        name: "三级菜单1-1-2",
                    }
                ]
            }
        ]
    },
    {
        id: "1",
        name: "一级菜单1",
        children: [
            {
                id: "1-1",
                name: "二级菜单1-1",
                children: [
                    {
                        id: "1-1-3",
                        name: "三级菜单1-1-3",
                    }
                ]
            }
        ]
    },
    {
        id: "2",
        name: "一级菜单2",
        children: [
            {
                id: "2-2",
                name: "二级菜单2-2",
            }
        ]
    },
];

目标结果如下:

[
  {
    "id": "1",
    "name": "一级菜单1",
    "children": [
      {
        "id": "1-1",
        "name": "二级菜单1-1",
        "children": [
          {
            "id": "1-1-1",
            "name": "三级菜单1-1-1"
          },
          {
            "id": "1-1-2",
            "name": "三级菜单1-1-2"
          },
          {
            "id": "1-1-3",
            "name": "三级菜单1-1-3"
          }
        ]
      }
    ]
  },
  {
    "id": "2",
    "name": "一级菜单2",
    "children": [
      {
        "id": "2-1",
        "name": "二级菜单2-1"
      },
      {
        "id": "2-2",
        "name": "二级菜单2-2"
      }
    ]
  },
  {
    "id": "3",
    "name": "一级菜单3"
  }
]

实现方法如下:

function mergeTree(target, source) {

    if (!target?.length && !source?.length) {
        if (target?.length) {
            return target;
        }
        if (source?.length) {
            return source;
        }
        return [];
    }

    const more = [];
    source.forEach((sNode) => {
        const tNode = target.find((tn) => tn.id === sNode.id);
        if (!tNode) {
            more.push(sNode);
            return;
        }

        const {children: sChildren, ...props} = sNode;
        Object.assign(tNode, props);
        mergeTree(tNode.children, sChildren);
    });
    target.push(...more);

    return target;
};

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值