如何对树形数据进行搜索?

90 阅读1分钟

预期结果:

    const treeList = [
      {
        id: 1,
        name: '根节点',
        children: [
          {
            id: 2,
            name: '子节点 1',
            children: [
              {
                id: 4,
                name: '子节点 1.1',
                children: [
                  {
                    id: 7,
                    name: '子节点 1.1.1'
                  }
                ]
              },
              {
                id: 5,
                name: '子节点 1.2'
              }
            ]
          },
          {
            id: 3,
            name: '子节点 2'
          },
          {
            id: 6,
            name: '子节点 3'
          }
        ]
      }
    ]

    filterTree(treeList, { name: '1' })
    
      /**预期结果:筛选出所有name字段包好'1'的数据
     * [
     *       {
     *         children: [
     *           {
     *             children: [
     *               {
     *                 children: [],
     *                 id: 7,
     *                 name: '子节点 1.1.1'
     *               }
     *             ],
     *             id: 4,
     *             name: '子节点 1.1'
     *           },
     *           {
     *             children: [],
     *             id: 5,
     *             name: '子节点 1.2'
     *           }
     *         ],
     *         id: 2,
     *         name: '子节点 1'
     *       }
     *     ]
     */


实现:

/**
 * 根据关键字过滤树形结构
 * @param treeList  树形结构
 * @param filter  过滤条件 如:{ name: 'test' }, 表示根据name字段筛选,可传多个字段
 * @param result  过滤结果
 * */
export function filterTree(treeList: any[], filter: Record<string, string>, result = []): any[] {
  if (!treeList) return []
  if (!filter || !Object.keys(filter).length || Object.values(filter).every((item) => !item)) return treeList
  for (const node of treeList) {
    // 只要有一个属性不匹配就视为失败
    const no = Object.keys(filter).some((key) => {
      if (typeof filter[key] === 'string') {
        // 字符串类型的模糊匹配
        return !node[key].toLowerCase().includes(filter[key].toLowerCase())
      } else {
        // 其他类型的精确匹配
        return node[key] !== filter[key]
      }
    })
    if (!no) {
      const cloneNode = { ...node, children: [] }
      result.push(cloneNode)
      if (node.children) {
        filterTree(node.children, filter, cloneNode.children)
      }
    } else {
      if (node.children) {
        filterTree(node.children, filter, result)
      }
    }
  }

  return result
}