/**
* 这个树状数据,是一个类目树。基本结构为
* [{
* 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