
本文详解如何基于 isotope.js 构建支持「跨分组 and、组内 or」语义的多条件过滤系统,解决类型(type)与标签(tag)同时筛选时逻辑混乱、优先级错乱的问题。
本文详解如何基于 isotope.js 构建支持「跨分组 and、组内 or」语义的多条件过滤系统,解决类型(type)与标签(tag)同时筛选时逻辑混乱、优先级错乱的问题。
在构建内容资源库、博客归档或产品展示页时,常需支持多维度筛选——例如按「内容类型」(如 Blog、Video)和「技术标签」(如 Ansible、Automation)联合过滤。Isotope.js 原生仅支持单一字符串选择器(如 .blogs-and-news.ansible),但默认无法自动处理「多个 type 或多个 tag 之间的组合爆炸式匹配」。若直接拼接类名,易陷入“最后点击项覆盖全局”的陷阱;而手动枚举所有组合又难以维护。
核心思路是:组内多选为 OR(即 tag: [ansible, automation] → 匹配含任一标签的元素),组间关系为 AND(即 type: blogs-and-news 且 tag: ansible → 必须同时满足)。这等价于笛卡尔积展开后的 CSS 类选择器列表:
{type: [a, b], tag: [x, y]}
→ .a.x, .a.y, .b.x, .b.y
为此,我们封装一个 Filter 类,职责清晰、可复用性强:
class Filter {
groups = {
type: [],
tag: []
};
// 切换指定分组中某值的选中状态
updateGroup(group, value, isSelected) {
const isActive = this.groups[group].includes(value);
if (isSelected && !isActive) {
this.groups[group].push(value);
} else if (!isSelected && isActive) {
this.groups[group] = this.groups[group].filter(v => v !== value);
}
}
// 生成符合 AND+OR 语义的完整选择器字符串
buildSelector() {
return Object.values(this.groups)
.reduce((selectors, values) => {
if (values.length === 0) return selectors;
return values.flatMap(v => selectors.map(s => `${s}.${v}`));
}, [''])
.join(', ');
}
// 一键更新 + 返回新选择器(供 isotope.arrange 调用)
updateSelector(group, value, isSelected) {
this.updateGroup(group, value, isSelected);
return this.buildSelector();
}
}
初始化后,在点击事件中调用即可:
document.addEventListener('DOMContentLoaded', () => {
const iso = new Isotope('.grid', {
itemSelector: '.resourceCard',
layoutMode: 'fitRows',
transitionDuration: '0.5s'
});
const filter = new Filter();
document.querySelectorAll('.rSidebar__options-li').forEach(el => {
el.addEventListener('click', function(e) {
e.preventDefault();
this.classList.toggle('selected');
const group = this.closest('[data-filter-group]').dataset.filterGroup;
const value = this.dataset.filter;
const isSelected = this.classList.contains('selected');
iso.arrange({ filter: filter.updateSelector(group, value, isSelected) });
});
});
});
✅ 关键优势说明:
- ✅ 逻辑健壮:空分组(如未选 type)自动跳过,避免生成无效选择器(如 ..ansible);
- ✅ 结构解耦:DOM 操作(点击/样式切换)与过滤逻辑完全分离,便于单元测试与后续扩展(如增加搜索、重置按钮);
- ✅ 可扩展性强:新增过滤维度(如 category、year)只需在 groups 中添加字段,无需修改核心算法;
- ✅ 性能友好:flatMap + map 链式计算复杂度为 O(n₁×n₂×…),实际项目中分组选项数通常 ≤10,组合总数可控。
⚠️ 注意事项:
- 确保 HTML 元素类名严格匹配 data-filter 值(如
对应 data-filter="blogs-and-news"); - 若某卡片应同时命中多个条件(如 Card 5 同属 blogs-and-news、ansible、automation),其 class 列表必须完整包含全部对应值;
- Isotope 的 filter 选项接受 CSS 选择器字符串或函数,本文方案使用字符串模式,简洁高效;若需更复杂逻辑(如属性匹配、文本搜索),可改用函数式 filter。
通过该方案,你将获得真正符合业务语义的多维筛选能力:单点触发精准收敛,多点叠加智能交集,告别“越点越少”或“只认最后一次”的交互反模式。











