You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何按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统一转小写,用户输入sS都能匹配到SaassSales Dashboard这类项。
  • 深拷贝保护原数据:每次过滤都返回新对象,避免修改原始数据导致后续逻辑出错。
  • 递归处理多层嵌套:不管是sub还是sub_child层级,都能正确遍历过滤。
  • 层级保留逻辑:若父节点自身不匹配但子节点有匹配项,父节点会被保留,保证用户能看到匹配项的层级结构,符合导航搜索的常规体验。

比如输入s时:

  • Saass(含s)会被保留,其子项中Sales DashboardSupport Dashboard会显示;
  • File Manager自身不含s,但子项Storages,所以File Manager会被保留且仅显示Storage子项。

内容的提问来源于stack exchange,提问作者Nikita Garg

火山引擎 最新活动