【JavaScript】データ属性で作る、フィルター・カテゴリー絞り込み機能

/

※本記事にはプロモーションが含まれています。

バニラのJavaScriptでカテゴリーの絞り込みフィルター機能の作り方を紹介します。
カテゴリー全てが表示されている状態からカテゴリーごとに絞り込みする際はタブの実装では管理が大変になってくるので絞り込み機能が役立ちます。

また、jQueryでの参考記事はたくさんありましたが、素のJavaSctiptで書かれているものが見つからなかった為JavaSctiptで作成したい方は参考にしてみてください。

サンプルコード

サンプルコードを記載します。
上段のliをクリックするとクリックしたカテゴリーと同じ下段のliが表示される仕組みです。
ギミックとしてはクリックしたボタンと同じデータ属性の値を持つものをJSで操作しています。
HTMLとCSSは最低限の記述のみ記載しておりますので、必要に応じて書き加えてください。
それでは次の章でJSを解説します。

See the Pen Untitled by fukuro (@fukuro722) on CodePen.

HTML

<ul class="filter">
  <li data-filter="all" class="is-active">全て表示</li>
  <li data-filter="vegetable">野菜</li>
  <li data-filter="drink">飲み物</li>
  <li data-filter="fruit">フルーツ</li>
 </ul>
 
<ul class="category">
  <li data-category="vegetable" class="is-show">ニンジン</li>
  <li data-category="vegetable" class="is-show">トマト</li>
  <li data-category="drink" class="is-show">コーラ</li>
  <li data-category="drink" class="is-show">牛乳</li>
  <li data-category="fruit" class="is-show">リンゴ</li>
  <li data-category="fruit" class="is-show">マンゴー</li>
</ul>

CSS

.filter li {
  cursor: pointer;
}

.filter li.is-active {
  color: red;
}

.category li {
  display: none;
}

.category li.is-show {
  display: block;
}

JavaScript

const filterButtons = document.querySelectorAll('[data-filter]');
const categoryContents = document.querySelectorAll('[data-category]');

filterButtons.forEach((filterButton) => {
  filterButton.addEventListener('click', buttonSwitch);
  filterButton.addEventListener('click', categoryFilter);
});

function buttonSwitch() {
  filterButtons.forEach((filterButton) => {
    filterButton.classList.remove("is-active");
    this.classList.add('is-active');
  });
}

function categoryFilter() {
  const buttonCategory = this.dataset.filter;
  const targetContents = document.querySelectorAll('[data-category="' + buttonCategory + '"]');

  categoryContents.forEach((categoryContent) => {

    categoryContent.animate([{
        opacity: 0
      },
      {
        opacity: 1
      }
    ], {
      duration: 600,
      fill: 'forwards'
    });

    if (buttonCategory == 'all') {
      categoryContent.classList.add('is-show');
    } else {
      categoryContent.classList.remove("is-show");
      targetContents.forEach((targetContent) => {
        targetContent.classList.add('is-show');
      });
    }
  });
}

コード解説

データ属性を持つ要素を全て取得

まずはボタンとコンテンツ部分の要素を全て変数に格納し準備を整えます。

// データ属「data-filter」を持つ要素(ボタン)を全て取得
const filterButtons = document.querySelectorAll('[data-filter]');

// データ属「data-category」を持つ要素(コンテンツ)をすべて取得
const categoryContents = document.querySelectorAll('[data-category]');

ボタンをクリックした時のイベントを定義

ボタンをクリックした際にクリックしたボタンをアクティブにするイベントとクリックしたボタンと同じカテゴリーを表示させるイベントを設定します。
関数の説明は下記で行います。

// ボタンをクリックした時のイベントを関数で定義
filterButtons.forEach((filterButton) => {
  // ① ボタンのアクティブ状態を操作する関数
  filterButton.addEventListener('click', buttonSwitch);

  // ② コンテンツ部分の絞り込みの関数 
  filterButton.addEventListener('click', categoryFilter);
});

【関数①】ボタンのアクティブ状態を操作

アクティブ状態のボタンのstyleをclassで定義しています。
ボタンをクリックしたら全ての.is-activeを外し、クリックした要素に再度.is-activeを追加して装飾を加えています。

// ボタンをクリックした時のイベント
function buttonSwitch() {
  filterButtons.forEach((filterButton) => {
    // ボタンについている「.is-active」を全て削除
    filterButton.classList.remove("is-active");
    // クリックしたボタンに「.is-active」を追加
    this.classList.add('is-active');
  });
}
<ul class="filter">
  <li data-filter="all" class="is-active">全て表示</li>
  <li data-filter="vegetable">野菜</li>
  <li data-filter="drink">飲み物</li>
  <li data-filter="fruit">フルーツ</li>
 </ul>
.filter li {
  cursor: pointer;
}

.filter li.is-active {
  color: red;
}

【関数②】 コンテンツ部分の絞り込み

最後にコンテンツ部分の関数です。
クリックしたボタンのデータ属性を取得し、データ属性の値によって対象のコンテンツの表示非表示を切り替えています。
また、表示非表示のアニメーションについてはclassの追加によるCSSのスタイルでは表示されてるコンテンツに対してアニメーションが効かない為、直接JavaScriptで操作をしています。

  function categoryFilter() {
    // クリックしたボタンのデータ属性の値を取得
    const buttonCategory = this.dataset.filter;
    const targetContents = document.querySelectorAll('[data-category="' + buttonCategory + '"]');

    // コンテンツ部分のアニメーション
    categoryContents.forEach((categoryContent) => {
      categoryContent.animate([{
          opacity: 0
        },
        {
          opacity: 1
        }
      ], {
        duration: 600,
      });

      // クリックしたデータ属性が「all」の場合、classを付与して全て表示
      if (buttonCategory == 'all') {
        categoryContent.classList.add('is-show');

      // all以外の場合、クリックしたデータ属性と同じコンテンツを表示する
      } else {
        categoryContent.classList.remove("is-show");
        targetContents.forEach((targetContent) => {
          targetContent.classList.add('is-show');
        });
      }
    });
  }

まとめ

データ属性を使うとこのようなフィルター機能を簡単に実装できるようになりますので、ぜひアレンジして試してみてください。

おすすめの書籍