SOURCE

/**
 * 这个树状数据,是一个类目树。基本结构为
 * [{
 *   id: 10,
 *   title: '一级类目名字10',
 *   childList: [{
 *      id: 20,
 *      title: '二级类目名字20',
 *      childList: [{
 *          id: 30,
 *          title: '三级类目名字30  要搜索的11111',
 *      },{
 *          id: 31,
 *          title: '三级类目名字31',
 *      }]
 *   },{
 *      id: 21,
 *      title: '二级类目名字21',
 *      childList: [{
 *          id: 32,
 *          title: '三级类目名字32',
 *      },{
 *          id: 33,
 *          title: '三级类目名字33 要搜索的2222',
 *      }]
 *   }]
 * }]
 */
const treeData = [{
    id: 10,
    title: '一级类目名字10',
    childList: [{
       id: 20,
       title: '二级类目名字20',
       childList: [{
           id: 30,
           title: '三级类目名字30  要搜索的11111',
       }, {
           id: 31,
           title: '三级类目名字31',
       }]
    },{
       id: 21,
       title: '二级类目名字21', 
       childList: [{
           id: 32,
           title: '三级类目名字32',
       }, {
           id: 33,
           title: '三级类目名字33 要搜索的2222',
       }]
    }]
}]

/**
 * 期望的搜索结果. 比如用用 "要搜索的11111" 过滤数据,数据应该是下面这样
 * 
 * {
 *   id: 10,
 *   title: '一级类目名字10',
 *   childList: [{
 *      id: 20,
 *      title: '二级类目名字20',
 *      childList: [{
 *          id: 30,
 *          title: '三级类目名字30  要搜索的11111', // 匹配到的数据,包括父节点的树状关系也保持一致
 *      }]
 *   }]
 * }
 * 
 * 如果想拼接处路径,基于以上数据结构很简单就能拼接出:
 * 
 * 一级类目名字10/二级类目名字20/三级类目名字30  要搜索的11111
 */

const searchTree = (keyword, list, childrenKey) => {
  if(!keyword) return [];

  const loop = (items) => {
    const newItems = [];
    // for……of……  是比较方便的循环数组的,也可以替换成普通的 for 循环
    for (const item of items) {
      // 先匹配子元素:因为子元素匹配上后,无论父元素匹配不匹配上,都应该把父元素返回,这样才能保持之前的树状结构
      const filteredChildren = item[childrenKey] && item[childrenKey].length > 0 && loop(item[childrenKey]);
      // 如果子元素匹配上了,那么当前的元素就是父元素,要加到返回的搜索结果里,并且保持同样的树状结构
      if(filteredChildren && filteredChildren.length > 0){
        newItems.push({ ...item, [childrenKey]: filteredChildren });

      //如果上面子元素没有匹配上,那么就匹配当前元素,看能否匹配上
      } else if(item.title.includes(keyword)){
        //如果匹配上了,就把当前元素赛进去;但因为子元素没有匹配上,所以要把子元素删除掉。
        const newItem = { ...item };  //不能直接在 item 上删除子元素,这样就改变原始的数据结构了。应该是新建一个新的对象,在这个新对象 newItem 上删除
        delete newItem[childrenKey];
        newItems.push(newItem);
      }
    }
    return newItems;
  }
  return loop(list);
}

const result = searchTree('要搜索的11111', treeData, 'childList')

console.log('原始的树状结构') 
console.log( JSON.stringify(treeData, null, 2) ) //用 JSON.stringify 是格式化了后好看一些

console.log('搜索后的树状结构') 
console.log( JSON.stringify(result, null, 2) )

console.log('要基于搜索后的结果,拼接出路径')
const paths = [];
const findPath = (previous, item) => {
    previous += item.title;
    if(item.childList){
        item.childList.forEach(v =>  findPath(previous, v));
    } else {
        paths.push(previous)
    }
}
result.forEach(item => findPath('', item));
console.log(paths)
console 命令行工具 X clear

                    
>
console