You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Isotope.js中实现多组筛选条件的组合筛选?

问题:Isotope.js 双维度筛选失效,同一组多选无法展示所有匹配内容

我有两个独立筛选维度:

  • tag(PDF、Article)
  • type(Blog & News、Case Studies)

尝试用Isotope.js实现双筛选布局,但当前总是最后点击的筛选条件优先级最高,组合筛选无法正常工作。具体需求:

  • 点击「Blog & News」应显示2篇文章(当前此功能正常)
  • 再点击「Case Studies」后,应同时展示案例研究和博客类文章,即同一筛选组内选中的所有选项对应的内容都要显示
  • 不同筛选组之间为“且”关系,比如选中「PDF」和「Case Studies」时,仅显示同时符合这两个条件的内容

官方文档说明arrange()方法支持多筛选实例,但我的场景中无效;尝试过concatValues()拼接筛选值,也未得到正确结果。


核心问题分析

  1. HTML标识错误:两个筛选组的data-filter-group都设置为type,导致Isotope无法区分不同筛选维度
  2. 筛选逻辑缺陷:原逻辑中同一筛选组只能单选,无法支持同一组内多选后展示所有匹配项
  3. 筛选器字符串生成错误:未按照Isotope的语法规则生成正确的组合筛选器(同一组内用逗号表示“或”,不同组间用空格表示“且”)

解决方案

1. 修正HTML的筛选组标识

将第一个筛选组(Filter by tag)的data-filter-group改为tag,确保两个维度的标识唯一:

<!-- tags -->
<div class="rSidebar__box">
  <span class="rSidebar__label d-block fw-bold">Filter by tag</span>
  <ul class="rSidebar__options button-group" data-filter-group="tag">
    <li class="rSidebar__options-li" data-filter=".pdf">
      <span class="rSidebar__options-square"></span>
      <span class="rSidebar__options-label d-block buttonTemp" data-filter=".pdf">PDF</span>
    </li>
    <li class="rSidebar__options-li" data-filter=".article">
      <span class="rSidebar__options-square"></span>
      <span class="rSidebar__options-label d-block buttonTemp" data-filter=".article">Article</span>
    </li>
  </ul>
</div>

<!-- type -->
<div class="rSidebar__box">
  <span class="rSidebar__label d-block fw-bold">Filter by type</span>
  <ul class="rSidebar__options button-group" data-filter-group="type">
    <li class="rSidebar__options-li" data-filter=".blogs-and-news">
      <span class="rSidebar__options-square"></span>
      <span class="rSidebar__options-label d-block buttonTemp" data-filter=".blogs-and-news">Blog & News</span>
    </li>
    <li class="rSidebar__options-li" data-filter=".case-study">
      <span class="rSidebar__options-square"></span>
      <span class="rSidebar__options-label d-block buttonTemp" data-filter=".case-study">Case Studies</span>
    </li>
  </ul>
</div>

2. 调整JavaScript筛选逻辑

修改筛选存储结构和筛选器生成逻辑,支持同一组内多选,同时生成符合Isotope语法的筛选字符串:

document.addEventListener('DOMContentLoaded', function() {
  var container = document.querySelector('.grid');
  const optionLinks = document.querySelectorAll('.rSidebar__options-li');

  var iso = new Isotope(container, {
    itemSelector: '.resourceCard',
    layoutMode: 'fitRows',
    transitionDuration: '0.5s',
  });

  // 存储每个筛选组的选中值,格式:{ tag: ['.pdf'], type: ['.blogs-and-news', '.case-study'] }
  var filters = {};

  // 生成符合Isotope语法的筛选器字符串
  function generateFilterString(filters) {
    // 遍历每个筛选组,将组内选中值用逗号拼接(或关系)
    const groupFilters = Object.values(filters).filter(group => group.length > 0)
      .map(group => group.join(','));
    
    // 不同组的筛选器用空格拼接(且关系),如果没有选中项则返回'*'(显示全部)
    return groupFilters.length > 0 ? groupFilters.join(' ') : '*';
  }

  function handleFilterClick(event) {
    var listItem = event.currentTarget; // 使用currentTarget避免事件冒泡问题
    var filterGroup = listItem.closest('.rSidebar__options').getAttribute('data-filter-group');
    var filterValue = listItem.getAttribute('data-filter');

    // 初始化该组的选中数组
    if (!filters[filterGroup]) {
      filters[filterGroup] = [];
    }

    // 切换选中状态:存在则移除,不存在则添加
    const valueIndex = filters[filterGroup].indexOf(filterValue);
    if (valueIndex > -1) {
      filters[filterGroup].splice(valueIndex, 1);
    } else {
      filters[filterGroup].push(filterValue);
    }

    // 生成筛选器并执行布局
    const filterString = generateFilterString(filters);
    iso.arrange({ filter: filterString });
  }

  optionLinks.forEach(function(optionLink) {
    optionLink.addEventListener('click', function(event) {
      event.preventDefault();
      this.classList.toggle('selected');
      handleFilterClick(event);
    });
  });
});

3. 关键逻辑说明

  • 筛选存储结构:用对象存储每个筛选组的选中值数组,比如{ tag: ['.pdf'], type: ['.blogs-and-news', '.case-study'] }
  • 筛选器生成规则:
    • 同一筛选组内的多个选项用逗号拼接,表示“或”关系(匹配组内任意一个选项)
    • 不同筛选组的筛选器用空格拼接,表示“且”关系(同时匹配所有组的筛选条件)
    • 若没有任何选中项,返回*表示显示全部内容
  • 事件处理优化:使用event.currentTarget避免事件冒泡导致的目标元素错误(比如点击到内部的span标签时仍能正确获取选中的li元素)

完整代码(含CSS)

.post {
  padding: 100px;
}

.rSidebar__box {
  margin-bottom: 30px;
}
.rSidebar__options {
  padding-left: 0;
}
.rSidebar__options-li {
  margin-bottom: 17px;
  display: flex;
  align-items: center;
  cursor: pointer;
  width: fit-content;
}
.rSidebar__options-li.selected .rSidebar__options-square {
  background-color: #185A7D;
}
.rSidebar__options-square {
  height: 20px;
  width: 20px;
  transition: all 0.5s ease;
  border: 2px solid #000000;
}
.rSidebar__options-label {
  margin-left: 10px;
}

.grid {
  display: flex;
  flex-wrap: wrap;
  margin: -14px 0 0 -14px;
}
.grid-item {
  box-sizing: border-box;
  width: calc(33.33% - 14px);
  margin: 14px 0 18px 14px;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://unpkg.com/isotope-layout@3/dist/isotope.pkgd.min.js"></script>

<div class="post">
  <div class="container">
    <div class="row justify-content-between">
      <!-- SIDEBAR -->
      <div class="col-3">
        <div class="rSidebar">
          <!-- tags -->
          <div class="rSidebar__box">
            <span class="rSidebar__label d-block fw-bold">Filter by tag</span>
            <ul class="rSidebar__options button-group" data-filter-group="tag">
              <li class="rSidebar__options-li" data-filter=".pdf">
                <span class="rSidebar__options-square"></span>
                <span class="rSidebar__options-label d-block buttonTemp" data-filter=".pdf">PDF</span>
              </li>
              <li class="rSidebar__options-li" data-filter=".article">
                <span class="rSidebar__options-square"></span>
                <span class="rSidebar__options-label d-block buttonTemp" data-filter=".article">Article</span>
              </li>
            </ul>
          </div>

          <!-- type -->
          <div class="rSidebar__box">
            <span class="rSidebar__label d-block fw-bold">Filter by type</span>
            <ul class="rSidebar__options button-group" data-filter-group="type">
              <li class="rSidebar__options-li" data-filter=".blogs-and-news">
                <span class="rSidebar__options-square"></span>
                <span class="rSidebar__options-label d-block buttonTemp" data-filter=".blogs-and-news">Blog & News</span>
              </li>
              <li class="rSidebar__options-li" data-filter=".case-study">
                <span class="rSidebar__options-square"></span>
                <span class="rSidebar__options-label d-block buttonTemp" data-filter=".case-study">Case Studies</span>
              </li>
            </ul>
          </div>
        </div>
      </div>
      <!-- END -->

      <!-- GRID -->
      <div class="col-7">
        <div class="grid">
          <article class="resourceCard grid-item case-study pdf"><span class="resourceCard__body-title">Case study, PDF post</span></article>
          <article class="resourceCard grid-item blogs-and-news"><span class="resourceCard__body-title">Blogs and news post</span></article>
          <article class="resourceCard grid-item blogs-and-news article"><span class="resourceCard__body-title">Blogs and news, article post</span></article>
        </div>
      </div>
      <!-- END -->
    </div>
  </div>
</div>

内容的提问来源于stack exchange,提问作者Freddy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 04:32:34