必须用 form 包裹筛选区,各维度用 fieldset 隔开并配 legend;name 须与后端 API 参数名一致;价格拆为 price_min/price_max;多选用同名 checkbox;提交用 FormData 自动处理,URL 同步需初始值、解析、设置三步闭环。

用 form 包裹筛选区,别用 div 模拟
多维度筛选不是靠一堆 div + 手动 JS 遍历实现的。一旦你把筛选区写成 <div class="filter-wrapper">,后续加价格区间、同步 URL、做无障碍支持、甚至只是改个字段名,JS 就得重写采集逻辑。原生 form 提供了隐性但关键的能力:form.elements 可遍历所有控件,new FormData(form) 自动合并同名 checkbox、跳过未选中项、忽略 disabled,连空值都不用额外过滤。
常见错误现象:
• 点击“筛选”按钮无反应 —— 忘了监听 submit 事件或没调 e.preventDefault()
• 多选品牌后只拿到最后一个值 —— 用了 name="brand" 的 radio,而不是多个同名 checkbox
• 刷新页面筛选丢失 —— 没把 FormData 序列化进 URL 或 localStorage
- 整个筛选区域必须用
<form id="filter-form">包裹 - 每个维度(如品牌、分类、评分)用
<fieldset>隔开,标题用<legend> - 所有
name值必须和后端 API 的 query 参数名完全一致,比如后端要?category=phone&rating=4,前端就写name="category"和name="rating" - 禁止使用
name="brand[]"这类 PHP 风格命名 ——FormData不识别方括号,后端收不到数据
价格区间、多选、单选混搭时怎么写 HTML 结构
不同筛选类型对 HTML 结构有明确要求,写错一个标签,JS 读出来的就是错的。比如价格不能用一个 input 写 “100-500”,必须拆成两个独立字段:price_min 和 price_max;品牌多选必须用同名 checkbox,而不是自己造 span + JS 绑定状态。
- 价格区间:
<input type="number" name="price_min">和<input type="number" name="price_max">,不要用range滑块——精度低、移动端兼容差、无法输入具体数值 - 品牌/分类等多选:
<input type="checkbox" name="brand" value="apple">,多个同名即可,浏览器自动处理提交逻辑 - 评分/状态等单选:
<select name="rating"><option value="">全部</option><option value="4">4星以上</option></select>,别用 radio group 模拟 select - 搜索关键词:
<input type="search" name="q">,语义清晰,部分浏览器会自动提供清空按钮
为什么 fieldsets 不是可选项,而是必须项
fieldset 不只是视觉分组,它承担着语义、可访问性和 DOM 可维护性的三重责任。没有它,屏幕阅读器无法理解“这一组是品牌筛选”,键盘用户无法用 Tab 进入/退出逻辑区块,JS 也失去按组批量操作的锚点(比如一键清空某维度)。
立即学习“前端免费学习笔记(深入)”;
- 每个
fieldset必须配legend,且文字要准确反映该组用途,例如<legend>品牌筛选</legend> - 禁用某组筛选时,直接给
fieldset加disabled,内部所有控件自动失效,FormData也会自动跳过它们 - 移动端点不中?检查
label是否完整包裹input,特别是 checkbox ——<label><input type="checkbox"> Apple</label>,不是<input><label>Apple</label> - 想动态显示/隐藏某组?操作
fieldset的hidden属性,比操作一堆div更安全、更语义化
筛选条件如何与 URL 同步,避免刷新丢失
用户复制链接发给别人、刷新页面、或回退到上一步时,筛选状态必须还在。这不能靠 localStorage 撑全场 —— 它不共享、不便于调试、也不利于 SEO。真实项目里,URL query string 是唯一可靠的状态载体。
- 提交时用
const params = Object.fromEntries(new FormData(form).entries())获取键值对 - 手动过滤掉空值(如
price_min: ""),再用URLSearchParams构建 query 字符串 - 用
history.replaceState更新 URL,不要用location.search直接跳转,否则页面会刷新 - 页面加载时,先从
location.search解析参数,再用 JS 设置对应控件的checked或value,注意触发input或change事件让 UI 同步 - 特别注意:如果后端返回的是 JSON 数据而非整页 HTML,那筛选状态更新后,只需重新请求数据并局部渲染,无需整页 reload
最易被忽略的一点:所有筛选字段的初始值必须和 URL 中的参数一致。比如 URL 带 ?brand=apple&rating=4,那页面一打开,对应 checkbox 就得是 checked,select 的 value 就得设为 "4" —— 这个同步动作一旦漏掉,用户就会觉得“我明明选了,怎么没生效”。



















