
本文介绍一种基于 data-filter 属性与 DOM 遍历的现代 JavaScript 过滤方案,避免为每个元素手动增删 active/hidden 类,提升代码可维护性与扩展性。
本文介绍一种基于 `data-filter` 属性与 dom 遍历的现代 javascript 过滤方案,避免为每个元素手动增删 `active`/`hidden` 类,提升代码可维护性与扩展性。
在构建食品分类筛选功能时(如早餐、午餐、饮品等),若对 8 个甚至更多食品项分别编写 classList.add('active') 和 classList.remove('hidden'),不仅冗长易错,更违背 DRY(Don’t Repeat Yourself)原则。真正的“干净代码”应聚焦抽象共性逻辑,而非重复操作个体元素。
✅ 推荐做法:语义化数据驱动 + 批量 DOM 操作
核心思路是:
- 给筛选按钮添加 data-filter="breakfast" 等语义化标识;
- 给食品容器添加对应的 data-filter="breakfast,lunch"(支持多标签);
- 通过 querySelectorAll 批量获取元素,用 forEach 统一处理;
- 利用 classList.toggle(className, condition) 实现精准显隐控制。
以下是精简、可复用的完整实现:
<!-- 筛选按钮组 --> <div class="filter-buttons"> <button class="active" data-filter="all">全部</button> <button data-filter="breakfast">早餐</button> <button data-filter="lunch">午餐</button> <button data-filter="drinks">饮品</button> </div> <!-- 食品列表(支持多分类) --> <div class="filter"> <div data-filter="breakfast">燕麦粥</div> <div data-filter="breakfast,lunch">三明治</div> <div data-filter="drinks">橙汁</div> <div data-filter="lunch">牛排</div> <div data-filter="drinks,breakfast">酸奶</div> <div data-filter="lunch,drinks">冰咖啡</div> </div>
/* 默认隐藏非 active 元素 */
.filter > div:not(.active) {
display: none;
}
/* 按钮激活态样式 */
.filter-buttons button.active {
background-color: #007bff;
color: white;
border-color: #007bff;
}
// 统一绑定按钮事件
document.querySelectorAll('.filter-buttons button').forEach(button => {
button.addEventListener('click', function() {
// 1. 重置所有按钮状态
document.querySelectorAll('.filter-buttons button')
.forEach(btn => btn.classList.remove('active'));
this.classList.add('active');
// 2. 获取当前筛选类型
const filterType = this.dataset.filter;
// 3. 批量处理食品项
const foodItems = document.querySelectorAll('.filter > div');
if (filterType === 'all') {
foodItems.forEach(el => el.classList.add('active'));
return;
}
// 4. 按 data-filter 匹配(支持逗号分隔的多标签)
foodItems.forEach(el => {
const itemFilters = el.dataset.filter?.split(',').map(s => s.trim()) || [];
const isActive = itemFilters.includes(filterType);
el.classList.toggle('active', isActive);
});
});
});
⚠️ 关键注意事项
- data-filter 值需严格一致:按钮的 data-filter="breakfast" 必须与食品 data-filter="breakfast" 完全匹配(区分大小写、空格);
-
多标签场景已兼容:如 可同时被“早餐”和“午餐”按钮激活;
- 性能友好:querySelectorAll 返回静态 NodeList,配合 forEach 避免重复 DOM 查询;
- 无障碍友好:建议为按钮添加 aria-pressed 属性以增强可访问性(进阶优化点);
- CSS 优先于 JS 控制显隐:推荐用 display: none 配合 .active 类控制可见性,而非直接操作 style.display,便于样式统一维护。
这种模式将业务逻辑(“哪些食品属于早餐?”)从 JS 中解耦至 HTML 的 data-* 属性,既提升可读性,又便于后端动态渲染或 CMS 管理。当新增第 9 个食品项时,你只需在 HTML 中添加一行带 data-filter 的
,无需修改任何 JS —— 这才是可扩展、易协作的清洁代码。











