如何按name键过滤多层嵌套对象数组并实现搜索功能
按name过滤多层嵌套对象数组的搜索实现
我来帮你解决这个多层嵌套数组的搜索过滤问题,这是个很常见的侧边栏导航搜索场景对吧?核心思路是递归遍历每个节点,既要判断节点自身的name是否匹配搜索关键词,还要处理子节点的过滤——毕竟如果父节点本身不匹配,但子节点有匹配项,我们得保留父节点才能让用户看到深层的匹配内容。
下面是完整的JavaScript实现方案,直接就能复用:
核心递归过滤函数
function filterNestedArray(data, searchText) { // 转小写实现不区分大小写的搜索,同时去除首尾空格 const lowerSearchText = searchText.toLowerCase().trim(); // 搜索文本为空时,返回原数据的深拷贝(避免修改原始数据) if (!lowerSearchText) { return JSON.parse(JSON.stringify(data)); } return data.reduce((acc, item) => { // 深拷贝当前项,防止污染原数据 const filteredItem = {...item}; // 如果当前项有子节点,递归过滤子数组 if (filteredItem.children && Array.isArray(filteredItem.children)) { filteredItem.children = filterNestedArray(filteredItem.children, searchText); } // 判断是否保留当前项:要么自身name匹配,要么过滤后的子节点不为空 const isNameMatch = filteredItem.name.toLowerCase().includes(lowerSearchText); const hasMatchingChildren = filteredItem.children && filteredItem.children.length > 0; if (isNameMatch || hasMatchingChildren) { acc.push(filteredItem); } return acc; }, []); }
实际使用示例
假设你有一个搜索输入框和导航渲染容器,可按以下方式绑定逻辑:
// 你的原始嵌套数据 const data = [ { state: 'saass', name: 'Saass', type: 'sub', icon: 'dashboard', active: true, children: [ { state: 'executive', name: 'Executive Dashboard', type: 'link' }, { state: 'sales', name: 'Sales Dashboard', type: 'link' }, { state: 'marketing',name: 'Marketing Dashboard', type: 'link' }, { state: 'support', name: 'Support Dashboard', type: 'link' }, { state: 'course', name: 'Course Detail', type: 'sub_child', children: [ { state: 'executive', name: 'Executive Dashboard', type: 'link' }, { state: 'marketing', name: 'Marketing Dashboard', type: 'link'} ] } ] }, { state: 'file-manager', name: 'File Manager', type: 'sub', icon: 'dashboard', active: false, children: [ { state: 'authentication', name: 'Authentication', type: 'link'}, { state: 'database', name: 'Database', type: 'link'}, { state: 'storage', name: 'Storage', type: 'link'} ] } ]; // 获取DOM元素 const searchInput = document.getElementById('searchInput'); const navContainer = document.getElementById('navContainer'); // 监听输入事件,实时过滤并渲染 searchInput.addEventListener('input', (e) => { const filteredData = filterNestedArray(data, e.target.value); renderNavigation(filteredData); }); // 导航渲染函数(可根据你的UI框架自定义) function renderNavigation(filteredData) { navContainer.innerHTML = ''; // 递归渲染节点 function renderItems(items) { items.forEach(item => { const itemEl = document.createElement('div'); itemEl.textContent = item.name; itemEl.style.margin = '4px 0'; navContainer.appendChild(itemEl); // 渲染子节点(缩进区分层级) if (item.children && item.children.length > 0) { const subContainer = document.createElement('div'); subContainer.style.paddingLeft = '20px'; navContainer.appendChild(subContainer); renderItems(item.children, subContainer); } }); } renderItems(filteredData); } // 初始化渲染原始数据 renderNavigation(data);
关键逻辑说明
- 不区分大小写搜索:将搜索文本和节点
name统一转小写,用户输入s或S都能匹配到Saass、Sales Dashboard这类项。 - 深拷贝保护原数据:每次过滤都返回新对象,避免修改原始数据导致后续逻辑出错。
- 递归处理多层嵌套:不管是
sub还是sub_child层级,都能正确遍历过滤。 - 层级保留逻辑:若父节点自身不匹配但子节点有匹配项,父节点会被保留,保证用户能看到匹配项的层级结构,符合导航搜索的常规体验。
比如输入s时:
Saass(含s)会被保留,其子项中Sales Dashboard、Support Dashboard会显示;File Manager自身不含s,但子项Storage含s,所以File Manager会被保留且仅显示Storage子项。
内容的提问来源于stack exchange,提问作者Nikita Garg




