You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

搜索筛选脚本异常隐藏匹配结果问题求助

原生JS搜索筛选脚本异常问题排查与修复

我正在编写原生JavaScript搜索筛选脚本,实现搜索输入框隐藏所有不包含搜索文本的列表项(分布在多个无序列表中),基础功能正常。但新增「若父容器(.filterSet)下所有子列表项均被隐藏,则隐藏该父容器」的功能后出现异常:部分匹配搜索文本的项被错误隐藏,例如输入“f”时,本该显示的“Foo”项被隐藏。

我已写出可用的jQuery版本代码,但希望保留原生JS实现,无法顺利将jQuery代码(尤其是$(this).find("ul.list-filters a").map(function(){部分)转译为原生JS。以下是相关代码:


原生JS代码

let filterList = [];
let filters = document.querySelectorAll('ul.list-filters a');

// Add the search input field:

let tEl = document.querySelector('#productListLeft');
let nEl = document.createElement('input');
nEl.setAttribute('id' ,  'filterSearch');
nEl.setAttribute('type' ,  'text');
nEl.setAttribute('placeholder' ,  'Search for filters');
tEl.prepend(nEl);

// Filter/hide items if they don't matched seached input text:

let filtersSearch = document.querySelector('#filterSearch');

for (let i = 0; i < filters.length; i++) {
    let filterName = filters[i].querySelector('span:first-of-type').textContent.toLowerCase(); 
    filterList.push(filterName);
}

console.log(filterList);


filtersSearch.addEventListener('keyup', (e) => {
    let text = filtersSearch.value.toLowerCase();

    for (let i = 0; i < filters.length; i++) {
        if (filterList[i].indexOf(text) < 0) {
            filters[i].style.display = 'none';
        } else {
            filters[i].style.display = 'block';
        }
    }
    
    // Hiding the parent div if all children are hidden (THIS IS THE PART THAT INCONCISTENTLY BREAKS THE FUNCTIONALITY AT SOME POINT:)

    let parentFilter = document.querySelectorAll(".filterSet");
    let visCheck = true;
    
    for(i = 0; i < parentFilter.length; i++) {
        let children = parentFilter[i].querySelectorAll('ul.list-filters a');
        for(x = 0; x < children.length; x++) {
            let child = children[x];
            
            if(child.style.display != "none") {
                visCheck = true;
            } else {
                visCheck = false;
            }
        }
        
        if (visCheck == false) {
            parentFilter[i].style.display = "none";
        } else if (visCheck == true) {
            parentFilter[i].style.display = "block";            
        }
    }
});

HTML结构

<div id="productListLeft">
  <div class="filterSet">
    <h4>Filters 1</h4>
    <ul class="list-filters">
      <li><a href="#"><span>Foo</span></a></li>
      <li><a href="#"><span>Bar</span></a></li>
      <li><a href="#"><span>Ball</span></a></li>
      <li><a href="#"><span>Next</span></a></li>
    </ul>
  </div>
  <div class="filterSet">
    <h4>Filters 2</h4>
    <ul class="list-filters">
      <li><a href="#"><span>Chair</span></a></li>
      <li><a href="#"><span>Kind</span></a></li>
      <li><a href="#"><span>Salt</span></a></li>
      <li><a href="#"><span>Horror</span></a></li>
    </ul>
  </div>
  <div class="filterSet">
    <h4>Filters 3</h4>
    <ul class="list-filters">
      <li><a href="#"><span>King</span></a></li>
      <li><a href="#"><span>Stagged</span></a></li>
      <li><a href="#"><span>Tomatoe</span></a></li>
      <li><a href="#"><span>Grilled</span></a></li>
    </ul>
  </div>
</div>

可用的jQuery代码

$('.filterSet').map(function(){
    let visCheck = true;
    $(this).find("ul.list-filters a").map(function(){
       if ( $(this).css("display") != "none" ) {
        visCheck = false;
       }
    });

    if ( visCheck == true ) {
       $(this).css("display", "none");
    } else {
       $(this).css("display", "block");
    }
});

问题根源与修复方案

原生脚本的异常来自两个核心问题:

  1. visCheck定义在父容器循环外部,导致前一个父容器的判断结果污染下一个的逻辑
  2. 子元素遍历中,每一次循环都会覆盖visCheck的值,最终只有最后一个子元素的状态决定父容器显示,同时逻辑与jQuery版本完全相反

修复后的原生JS代码

let filterList = [];
let filters = document.querySelectorAll('ul.list-filters a');

// 添加搜索输入框
const tEl = document.querySelector('#productListLeft');
const nEl = document.createElement('input');
nEl.setAttribute('id', 'filterSearch');
nEl.setAttribute('type', 'text');
nEl.setAttribute('placeholder', 'Search for filters');
tEl.prepend(nEl);

const filtersSearch = document.querySelector('#filterSearch');

// 预存所有筛选项文本(小写)
for (let i = 0; i < filters.length; i++) {
    const filterName = filters[i].querySelector('span:first-of-type').textContent.toLowerCase(); 
    filterList.push(filterName);
}

filtersSearch.addEventListener('keyup', () => {
    const text = filtersSearch.value.toLowerCase();

    // 第一步:筛选单个列表项的显示/隐藏
    for (let i = 0; i < filters.length; i++) {
        filters[i].style.display = filterList[i].includes(text) ? 'block' : 'none';
    }
    
    // 第二步:控制父容器的显示/隐藏
    const parentFilters = document.querySelectorAll(".filterSet");
    
    for (let i = 0; i < parentFilters.length; i++) {
        const parent = parentFilters[i];
        const children = parent.querySelectorAll('ul.list-filters a');
        let allHidden = true;
        
        for (let x = 0; x < children.length; x++) {
            if (children[x].style.display !== "none") {
                allHidden = false;
                break; // 找到可见项后直接终止循环,提升性能
            }
        }
        
        parent.style.display = allHidden ? "none" : "block";
    }
});

关键修复点

  • 将allHidden(原visCheck)移到每个父容器的循环内部,确保判断独立
  • 修正逻辑:默认假设所有子元素都隐藏,只要找到一个可见项就标记父容器需要显示
  • 找到可见项后立即终止子元素循环,减少无效遍历
  • 使用includes()替代indexOf(),代码更直观

jQuery代码转译的原生JS版本

如果仅需转译提供的jQuery代码,对应实现如下:

const parentFilters = document.querySelectorAll('.filterSet');
parentFilters.forEach(parent => {
    let visCheck = true;
    const children = parent.querySelectorAll('ul.list-filters a');
    children.forEach(child => {
        // 获取计算后的实际显示状态,避免inline样式未设置的问题
        const displayStyle = window.getComputedStyle(child).display;
        if (displayStyle !== 'none') {
            visCheck = false;
        }
    });
    parent.style.display = visCheck ? 'none' : 'block';
});

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 05:24:54