树结构过滤(查找)数据,父级一起带出来。

搜索到的结果

树形结构数据的高效过滤与父级关联方案
问题场景:树形数据的智能搜索
在实际开发中,我们经常需要处理树形结构数据的搜索过滤,并且要求能够同时返回匹配节点及其所有父级节点。这种需求在文件系统、组织架构、分类目录等场景中十分常见。本文将深入分析一个树形数据过滤方案,并提供多种优化思路。
基础实现方案分析
直接上代码。。。。
/**
* @author 过滤数据
* @param {*} value
* @param {*} arr
* @return {*} []
*/
const TreeDataList = (value:any = '', arr:any) => {
if (!arr) {
return []
}
let newList:any[] = [];
arr.forEach((item:any) => {
if (item.title1.indexOf(value) > -1) {
const Children = TreeDataList(value, item.children);
const obj = {
...item,
children: Children
}
console.log(item,obj,Children);
newList.push(obj);
} else {
if (item.children && item.children.length > 0) {
const Children = TreeDataList(value, item.children);
const obj = {
...item,
children: Children
};
if (Children && Children.length > 0) {
newList.push(obj);
}
}
}
});
return newList;
};
当前实现特点:
-
递归遍历树形结构
-
匹配包含关键词的节点(title1)
-
自动保留有效子节点的父级
-
返回保持原有结构的新树
优化方案一:性能提升版
const filterTree = (keyword = '', treeData = []) => {
if (!treeData.length) return [];
return treeData.reduce((result, node) => {
// 检查当前节点是否匹配
const isMatch = node.title1.includes(keyword);
// 递归处理子节点
const children = filterTree(keyword, node.children || []);
// 如果当前节点匹配或有匹配的子节点,则保留该节点
if (isMatch || children.length) {
result.push({
...node,
children: children.length ? children : undefined
});
}
return result;
}, []);
};
优化点:
-
使用
reduce替代forEach,减少中间变量 -
简化条件判断逻辑
-
使用
includes替代indexOf,语义更清晰 -
空子节点设为undefined而非空数组,减少内存占用
优化方案二:支持多字段搜索
const filterTreeAdvanced = (
keyword = '',
treeData = [],
searchFields = ['title1', 'title2', 'code']
) => {
return treeData.filter(node => {
// 检查当前节点是否匹配任意搜索字段
const isNodeMatch = searchFields.some(
field => node[field]?.toString().includes(keyword)
);
// 递归处理子节点
const matchedChildren = filterTreeAdvanced(
keyword,
node.children || [],
searchFields
);
// 保留当前节点条件
return isNodeMatch || matchedChildren.length;
}).map(node => ({
...node,
children: filterTreeAdvanced(keyword, node.children || [], searchFields)
}));
};
增强功能:
-
支持多个字段的搜索
-
自动处理字段值为非字符串的情况
-
更简洁的函数式编程风格
优化方案三:非递归实现(避免栈溢出)
const filterTreeIterative = (keyword, treeData) => {
const stack = [...treeData.map(node => ({ node, parent: null }))];
const result = [];
while (stack.length) {
const { node, parent } = stack.pop();
const isMatch = node.title1.includes(keyword);
let shouldKeep = isMatch;
// 处理子节点
const children = (node.children || []).map(child => ({
node: child,
parent: node
}));
// 如果有匹配的子节点,当前节点也需要保留
const hasMatchingChildren = children.some(
({ node: child }) => child.title1.includes(keyword)
);
shouldKeep = shouldKeep || hasMatchingChildren;
if (shouldKeep) {
const newNode = { ...node, children: [] };
if (parent) {
parent.children.push(newNode);
} else {
result.push(newNode);
}
}
// 将子节点压入栈中
stack.push(...children);
}
return result;
};
优势:
-
使用迭代替代递归,避免栈溢出风险
-
显式处理父子关系,逻辑更清晰
-
适合处理深度很大的树结构
性能对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 基础递归 | 实现简单 | 性能一般,可能栈溢出 | 小规模数据 |
| 优化递归 | 代码简洁 | 仍存在递归风险 | 中等规模数据 |
| 多字段搜索 | 功能强大 | 性能开销稍大 | 需要多字段搜索 |
| 迭代实现 | 无栈溢出风险 | 代码较复杂 | 超深树结构 |
最佳实践建议
-
数据规模考虑:
-
<1000节点:递归方案即可
-
1000节点:考虑迭代实现
-
-
搜索体验优化:
-
添加防抖处理(300ms)
-
支持模糊搜索(考虑正则表达式)
-
高亮显示匹配内容
-
总结
树形数据的过滤搜索是一个常见但具有挑战性的需求。本文从基础实现出发,逐步介绍了多种优化方案,每种方案都有其适用场景。在实际项目中,建议:
-
根据数据规模选择合适算法
-
考虑添加缓存机制优化重复搜索
-
做好错误处理和性能监控
-
在用户体验和性能之间取得平衡
希望这些方案能为你的树形数据搜索需求提供有价值的参考!
这篇博客介绍了如何使用JavaScript实现树结构数据的过滤和查找功能,通过递归遍历每个节点,当节点的title1属性包含指定值时,将其与子节点一并保留。代码中展示了如何构建新的过滤后的数据列表,并在控制台输出了处理过程。
1189





