静态页多条件筛选应使用包裹控件并用FormData读取,数据≤1000行可前端实时过滤,需统一防抖、精确匹配、.hidden类控制显隐,避免DOM遍历错误和display误设。

静态页做多条件筛选,本质是用 JavaScript 驱动 DOM 显隐,不是靠 HTML 自己“筛选”。数据量 ≤1000 行时,前端实时过滤完全可行;超过就得切后端分页,否则卡死。
必须用 <form></form> 包裹筛选控件,别用 <div>
<p>不用 <code><form></form> 的后果很直接:你得手动遍历每个 <input>、判断 type、处理 checkbox 多选、拼 query string——DOM 一改,JS 就断。而 <form></form> 天然支持:
-
form.elements 直接拿到所有控件,包括 <select multiple></select> 和未选中的 checkbox
-
new FormData(form) 自动忽略未选中的 checkbox、合并同名 name(如多个 brand)、跳过 disabled 项
-
form.checkValidity() 可配合 required 做基础校验,不用自己写正则
form.elements 直接拿到所有控件,包括 <select multiple></select> 和未选中的 checkbox
new FormData(form) 自动忽略未选中的 checkbox、合并同名 name(如多个 brand)、跳过 disabled 项form.checkValidity() 可配合 required 做基础校验,不用自己写正则常见错误:<div class="filter-form"> + <code>document.querySelectorAll('[name]') 硬捞——一旦加个动态渲染的筛选项,name 漏了或拼错,整个采集逻辑就失效。
FormData 读取值时注意空值和多选
用户没填的字段,FormData 依然会返回空字符串,不是 undefined;多个同名 checkbox 被选中时,FormData.entries() 会返回多条记录,不是数组。
立即学习“前端免费学习笔记(深入)”;
- 用
Object.fromEntries(formData.entries())得到的是单值对象,同名多选会被后一个覆盖 - 需要多选语义(如
brand=apple&brand=samsung),得用Array.from(formData.entries())手动归类 - 价格区间这种成对字段(
price_min/price_max)要显式判断是否非空:if (params.price_min !== "" && params.price_max !== "") { ... } -
name="brand[]"是 PHP 风格,在纯 HTML/JS 场景下无效,FormData不识别方括号
前端实时过滤时,所有条件必须在一个 filter 回调里合并
链式 .filter().filter() 或嵌套 if 容易漏行或错显:中间某次过滤把行筛没了,后续条件就无从判断;嵌套 if 容易写成“满足任一”而非“全部满足”。
- 正确做法:遍历每行
<tr>,对每个条件单独计算布尔值,再用 <code>&&连接 - 每个条件默认返回
true(即不限制),避免空输入导致整行被隐藏 - 精确匹配建议清洗文本:
const clean = str?.trim().replace(/[\s\uFEFF\xA0]+/g, ' '),再用===比对,比includes更可控 - 只遍历
<tbody> 下的 <code><tr>,不碰 <code><thead> 或 <code><tfoot>,避免误操作 <h3>显隐控制别碰 <code>style.display,用.hidden类统一管理直接设
el.style.display = "none"再恢复,会丢失原始display值(比如原来是inline-flex,恢复成block就错位);移动端频繁触发重排,滑动卡顿明显。- 推荐 CSS 方案:
.item.hidden { opacity: 0; pointer-events: none; transition: opacity 0.2s; } - JS 里只做一件事:
el.classList.toggle("hidden", !matches) - 这样既不破坏文档流,动画自然,也不影响已绑定的事件监听器
- 初始化时统一给所有待筛选项加
.hidden,点击筛选时只对匹配项移除该类
最易被忽略的是:多个输入框共用一个防抖后的统一过滤回调,而不是每个
input单独绑事件执行一次完整过滤——否则用户同时改两个框,后触发的那个会覆盖前一个的结果。 - 推荐 CSS 方案:



















