应使用语义化html5标签:一级分类用包裹并配,单品用而非或,规格用结构化;筛选依赖data-category等属性,状态存数组,显隐通过.hidden类控制。

用 <section></section> 划分分类区块,别堆在同一个 <div> 里
<p>把所有产品塞进一个 <code><div class="product-list"> 再靠 JS 拉数据筛选,后期维护和语义化都吃力。真实项目里,每个一级分类(如「笔记本」「手机」「配件」)应独立包裹在 <code><section id="laptop"></section> 中,并配 <h2></h2> 标题。这样既支持锚点跳转(#laptop),又方便 CSS 按区块控制间距、背景或响应式断点。
常见错误是用 <div class="category-laptop"> 这类 class 做结构划分——它没语义,无法被屏幕阅读器识别,也不利于 SEO。而 <code><section></section> 是 HTML5 明确定义的分区元素,浏览器和爬虫都认。
单品必须用 <article></article> 包裹,不是 <div> 或 <code><li>
每个产品条目不是普通容器,而是独立可复用、可分享、可订阅的内容单元。<article></article> 才是语义正确的标签。里面嵌套 <figure></figure> 放主图 + <figcaption></figcaption> 放标题/价格,再用 <dl></dl> 展示规格参数(品牌、CPU、内存等),比一堆 <p></p> 更结构化。
不推荐用 <li>:列表项隐含“顺序”或“并列集合”,但电商列表通常不强调顺序,且常需脱离列表上下文单独渲染(比如弹窗详情、推荐位复用);<div> 则完全丢失语义。
<h3>
<code>data-category 是筛选唯一可信源,别碰 class 或 id
筛选逻辑依赖的数据必须干净、单一、可预测。给 <article></article> 加 data-category="laptop",JS 就能用 document.querySelectorAll('[data-category="laptop"]') 精准取数。这个值应由后端统一返回,前端只读不拼接。
容易踩的坑:
- 用
class="product laptop new"后靠.laptop查询 —— 一旦有laptop-pro类就误匹配 - 把分类存在
id="prod-123-laptop"里 —— 解析字符串脆弱,且id必须唯一,不能重复用于多个产品 - 筛选时直接改
style.display—— 会覆盖原有 display 值(如inline-block变成block导致错行)
正确做法是加 .hidden 类控制显隐,样式写 .product.hidden { opacity: 0; pointer-events: none; },再配合 transition 做淡入淡出。
多级筛选状态必须存数组,别硬编码 if/else
用户勾选「笔记本」+「新品」时,筛选条件不是 if (cat === "laptop" || cat === "new")。这种写法一加新分类就得改 JS,不可持续。
应该维护一个实时更新的数组:
const activeCategories = ["laptop", "new"]; const activeTags = ["free-shipping", "in-stock"];
判断逻辑统一为:
const elCat = element.dataset.category;
const elTag = element.dataset.tag;
const show = activeCategories.includes(elCat) && activeTags.includes(elTag);
element.classList.toggle("hidden", !show);
重置按钮只需清空数组并遍历移除 .hidden,不用重建 DOM 或重载 HTML 字符串 —— 否则事件监听器全丢,图片懒加载也失效。
真正难的不是写出筛选效果,而是让分类字段、状态管理、DOM 更新三者解耦。只要 data-category 值稳定、数组状态可追踪、显隐靠 class 控制,后续加搜索、排序、分页就只是叠加逻辑,不是推倒重来。











