用input事件监听搜索、textContent匹配、classList.toggle控制显隐,可实现响应快、不卡顿、语义清晰的过滤列表;因其能捕获粘贴、输入法上屏等所有输入变化,且兼容IE9+。

直接用 input 监听 input 事件 + textContent 匹配 + classList.toggle 控制显隐,就能做出响应快、不卡顿、语义清晰的搜索过滤列表。别用 innerHTML 替换整个列表,也别在循环里反复设 display。
为什么用 input 事件而不是 keyup
因为 input 能捕获所有输入变化:粘贴、剪切、中文输入法上屏、语音输入、自动填充——而 keyup 在用户还没完成输入(比如拼音还没选字)时就触发,导致匹配错乱或漏匹配。
- 用户粘贴 “React” 时,
input只触发一次;keyup可能触发多次(Ctrl+V、V、再一个字母) - 移动端中文输入法下,
keyup常在“选词前”就上报拼音,搜 “shu” 却匹配不到 “书” -
input是标准事件,兼容性好(IE9+),无需 polyfill
怎么避免大小写和空格干扰匹配
统一转小写只是基础;更关键的是对用户输入做清洗:去首尾空格、合并连续空格、忽略全角空格。否则搜 “ react ” 或 “react ”(中文空格)会失败。
- 正确写法:
const keyword = searchInput.value.trim().replace(/s+/g, ' ').toLowerCase() - 匹配时别只用
includes(),尤其当数据含 HTML 标签(如<span>Vue</span>)——先取textContent,再比对 - 如果要支持“任意词都命中”,把
keyword.split(' ').filter(Boolean)后逐个includes,而不是拼成正则(避免/[.*+?^${}()|[]\]/g漏转义)
隐藏列表项该用 display: none 还是 hidden 类
用 classList.toggle("hidden") 配合 CSS 类最稳妥。硬设 style.display = "none" 会覆盖元素原本的 display 类型(比如 inline-flex 变成 block),引发布局错位。
立即学习“前端免费学习笔记(深入)”;
- CSS 写:
.hidden { display: none; }或更优:.hidden { opacity: 0; visibility: hidden; pointer-events: none; }(保留占位或支持过渡动画) - 重置时别遍历 DOM 再一个个删
display,直接document.querySelectorAll(".item").forEach(el => el.classList.remove("hidden")) - 注意:不要给
.hidden加!important,否则和组件库样式冲突难调试
大数据量时卡顿?防抖不是唯一解
200 条以内列表,防抖反而增加延迟感;真卡顿往往来自 DOM 重排——每次 display 切换都会触发 layout。核心是减少重排次数,而非单纯加 setTimeout。
- 把所有匹配判断做完,再批量操作 DOM:先收集要显示/隐藏的元素引用,最后统一
toggle - 如果列表超 500 条,改用虚拟滚动(如
react-window)或服务端分页,前端过滤已不现实 - 防抖阈值别设 300ms:用户打字节奏约 200ms/字,设 150ms 更自然;且要
clearTimeout前次定时器,否则快速输入仍会滞后
最容易被忽略的是「空搜索」和「无结果」状态处理:清空输入框后必须恢复全部项,不能留着上次的隐藏状态;没匹配到时,要在列表容器内插入一个 <li class="no-result">未找到匹配项</li>,而不是让容器变空——否则高度塌陷、滚动位置丢失、无障碍阅读器无法感知。



















