【jQuery】複数の選択項目での絞り込み処理 + 遷移元からのアンカー付リンク ( hashタグありリンク ) で遷移後にタブ切り替え

[ ID : 11623 ]
ゴールド
【jQuery】複数の選択項目での絞り込み処理 + 遷移元からのアンカー付リンク ( hashタグありリンク ) で遷移後にタブ切り替え
実装目安
3分

概要

複数の選択項目での絞り込み処理と遷移元から所定のアンカーリンク(ハッシュタグを付与されたURL)で遷移してきた場合に対応するタブ(カテゴリ)をカレント状態にする処理の実装について

用途・要件

  • 複数の選択項目で絞り込みを実装したい場合に使用。
  • 絞り込みトリガーはinput(ラジオボタン・チェックボックス)で実装。
  • 絞り込み対象アイテムにdata属性(data-*)を複数設定。*にはトリガーのname属性と同じ値を設定。
  • チェックボックス(サブカテゴリ)は択一選択で実装(チェックは全て外すことも可能)。
  • 他のページ(遷移元)から特定のアンカーリンクで遷移してきた場合、ページをロード時に対応するタブをカレントにする。

検証ブラウザ(PC)

  • Google Chrome(最新)
  • Safari(最新)
  • Firefox(最新)
  • Microsoft Edge(最新)

実装



HTML

<ul class="c-link">
    <li class="c-link__item">
        <a href="https://konocode.jp/11623/#all" target="_blank" class="c-link__link">ALL</a>
    </li>
    <li class="c-link__item">
        <a href="https://konocode.jp/11623/#cat01" target="_blank" class="c-link__link">カテゴリ01</a>
    </li>
    <li class="c-link__item">
        <a href="https://konocode.jp/11623/#cat02" target="_blank" class="c-link__link">カテゴリ02</a>
    </li>
    <li class="c-link__item">
        <a href="https://konocode.jp/11623/#cat03" target="_blank" class="c-link__link">カテゴリ03</a>
    </li>
</ul>

<div class="c-selector js-filter-box">
    <label class="c-selector__label">
        <input id="all" type="radio" name="cat" value="" class="c-selector__input" checked>
        <span class="c-selector__txt">ALL</span>
    </label>
    <label class="c-selector__label">
        <input id="cat01" type="radio" name="cat" value="カテゴリ01" class="c-selector__input">
        <span class="c-selector__txt">カテゴリ01</span>
    </label>
    <label class="c-selector__label">
        <input id="cat02" type="radio" name="cat" value="カテゴリ02" class="c-selector__input">
        <span class="c-selector__txt">カテゴリ02</span>
    </label>
    <label class="c-selector__label">
        <input id="cat03" type="radio" name="cat" value="カテゴリ03" class="c-selector__input">
        <span class="c-selector__txt">カテゴリ03</span>
    </label>
</div>

<div class="c-selector-2 js-filter-box">
    <label class="c-selector-2__label">
        <input type="checkbox" name="sub-cat" value="" class="c-selector-2__input" checked>
        <span class="c-selector-2__txt">絞り込み</span>
    </label>
    <label class="c-selector-2__label">
        <input type="checkbox" name="sub-cat" value="サブカテゴリ01" class="c-selector-2__input">
        <span class="c-selector-2__txt">サブカテゴリ01</span>
    </label>
    <label class="c-selector-2__label">
        <input type="checkbox" name="sub-cat" value="サブカテゴリ02" class="c-selector-2__input">
        <span class="c-selector-2__txt">サブカテゴリ02</span>
    </label>
</div>

<ul class="c-list">
    <li class="c-list__item js-filter-target" data-cat="カテゴリ01" data-sub-cat="サブカテゴリ01">カテゴリ01 : サブカテゴリ01</li>
    <li class="c-list__item js-filter-target" data-cat="カテゴリ01" data-sub-cat="サブカテゴリ02">カテゴリ01 : サブカテゴリ02</li>
    <li class="c-list__item js-filter-target" data-cat="カテゴリ02" data-sub-cat="サブカテゴリ01">カテゴリ02 : サブカテゴリ01</li>
    <li class="c-list__item js-filter-target" data-cat="カテゴリ02" data-sub-cat="サブカテゴリ02">カテゴリ02 : サブカテゴリ02</li>
    <li class="c-list__item js-filter-target" data-cat="カテゴリ03" data-sub-cat="サブカテゴリ01">カテゴリ03 : サブカテゴリ01</li>
    <li class="c-list__item js-filter-target" data-cat="カテゴリ03" data-sub-cat="サブカテゴリ02">カテゴリ03 : サブカテゴリ02</li>
</ul>

SCSS

/* ---------------------------------------------
* is-hide
--------------------------------------------- */
.is-hide {
display: none;
}

/* ---------------------------------------------
* c-link
--------------------------------------------- */
.c-link {
$breakpoint-sp: 767;
display: flex;
align-items: center;
gap: 2em;
padding: 2em 1.5em;
background-color: #A9A9A9;

&__link {
color: #fff;
text-decoration: underline;

@media screen and (min-width: #{$breakpoint-sp + 1}px) {
&:hover {
text-decoration: none;
}
}
}
}

/* ---------------------------------------------
* c-selector
--------------------------------------------- */
.c-selector {
$host: &;
display: flex;
margin-top: 4em;
max-width: 1000px;

&__label {
display: flex;
flex-direction: column;
width: calc(100% / 4);
cursor: pointer;
}

&__input {
display: none;
opacity: 0;
}

&__txt {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
padding: 1em 5%;
border: 1px solid #000;
text-align: center;

#{$host}__label:nth-of-type(n+2) & {
border-left: none;
}

#{$host}__input:checked + & {
color: #fff;
background-color: #223a70;
border-color: #223a70;
}
}
}

/* ---------------------------------------------
* c-selector-2
--------------------------------------------- */
.c-selector-2 {
$host: &;
display: flex;
align-items: center;
gap: .5em;
margin-top: 2em;

&__label {
cursor: pointer;

&:first-of-type {
pointer-events: none;
}
}

&__input {
display: none;
opacity: 0;
}

&__txt {
display: block;
padding: .5em 1em;
border: 1px solid #000;
border-radius: 99px;
text-align: center;

#{$host}__label:not(:first-child) #{$host}__input:checked + & {
color: #fff;
background-color: #007bbb;
border-color: #007bbb;
}

#{$host}__label:first-child & {
padding: .5em;
border-color: transparent;
border-radius: 0;
}
}
}

/* ---------------------------------------------
* c-list
--------------------------------------------- */
.c-list {
list-style: disc;
padding-left: 2em;
margin-top: 2em;

&__item {
margin-top: .5em;

&:first-of-type {
margin-top: 0;
}
}
}

CSS

/* ---------------------------------------------
*   is-hide
--------------------------------------------- */
.is-hide {
    display: none;
}

/* ---------------------------------------------
*   c-link
--------------------------------------------- */
.c-link {
    display: flex;
    align-items: center;
    gap: 2em;
    padding: 2em 1.5em;
    background-color: #A9A9A9;
}
.c-link__link {
    color: #fff;
    text-decoration: underline;
}
@media screen and (min-width: 768px) {
    .c-link__link:hover {
        text-decoration: none;
    }
}

/* ---------------------------------------------
*   c-selector
--------------------------------------------- */
.c-selector {
    display: flex;
    margin-top: 4em;
    max-width: 1000px;
}
.c-selector__label {
    display: flex;
    flex-direction: column;
    width: 25%;
    cursor: pointer;
}
.c-selector__input {
    display: none;
    opacity: 0;
}
.c-selector__txt {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-grow: 1;
    padding: 1em 5%;
    border: 1px solid #000;
    text-align: center;
}
.c-selector__label:nth-of-type(n+2) .c-selector__txt {
    border-left: none;
}
.c-selector__input:checked + .c-selector__txt {
    color: #fff;
    background-color: #223a70;
    border-color: #223a70;
}

/* ---------------------------------------------
*   c-selector-2
--------------------------------------------- */
.c-selector-2 {
    display: flex;
    align-items: center;
    gap: 0.5em;
    margin-top: 2em;
}
.c-selector-2__label {
    cursor: pointer;
}
.c-selector-2__label:first-of-type {
    pointer-events: none;
}
.c-selector-2__input {
    display: none;
    opacity: 0;
}
.c-selector-2__txt {
    display: block;
    padding: 0.5em 1em;
    border: 1px solid #000;
    border-radius: 99px;
    text-align: center;
}
.c-selector-2__label:not(:first-child) .c-selector-2__input:checked + .c-selector-2__txt {
    color: #fff;
    background-color: #007bbb;
    border-color: #007bbb;
}
.c-selector-2__label:first-child .c-selector-2__txt {
    padding: 0.5em;
    border-color: transparent;
    border-radius: 0;
}

/* ---------------------------------------------
*   c-list
--------------------------------------------- */
.c-list {
    list-style: disc;
    padding-left: 2em;
    margin-top: 2em;
}
.c-list__item {
    margin-top: 0.5em;
}
.c-list__item:first-of-type {
    margin-top: 0;
}

JS

$(function () {
    'use strict';

    const $triggerBox = $('.js-filter-box'); //絞り込みエリア(radio / checkbox)
    const $checkbox = $triggerBox.find('input[type="checkbox"]'); //絞り込みエリア(checkbox)
    const $trigger = $('input'); //絞り込みトリガー
    const $target = $('.js-filter-target'); //絞り込み対象のアイテム
    const hideClass = 'is-hide'; // 絞り込み対象外の場合に付与されるクラス(非表示にする)

    $checkbox.on('change', function () {
        const $this = $(this);

        //チェックボックスを択一選択にする
        if ($this.prop('checked')) {
            $this.closest($triggerBox).find($checkbox).prop('checked', false);
            $this.prop('checked', true);
        }
    });

    $triggerBox.find($trigger).on('change', function () {
        filterItem(); //絞り込み

        //絞り込み処理
        function filterItem() {
            $target.removeClass(hideClass); //一旦、全て表示

            const triggerBoxLength = $triggerBox.length;

            for (let i = 0; i < triggerBoxLength; i++) {
                const name = $triggerBox.eq(i).find($trigger).attr('name'),
                    selectedData = getSelectedItem(name); // 選択項目を取得

                // 選択項目がない、またはALLを選択している場合はスキップ
                if (selectedData.length === 0 || selectedData[0] === '') {
                    continue;
                }

                // 各絞り込み対象アイテムをチェック
                const targetLength = $target.length;

                for (let j = 0; j < targetLength; j++) {
                    const itemData = $target.eq(j).data(name); // アイテムの設定項目を取得

                    // 配列内の項目と比較して、絞り込み対象外の場合アイテムを非表示
                    if (selectedData.indexOf(itemData) === -1) {
                        $target.eq(j).addClass(hideClass);
                    }
                }
            }
        }

        // inputで選択されている項目を取得し、配列に格納
        function getSelectedItem(name) {
            const selectedData = [];

            $('[name=' + name + ']:checked').each(function () {
                selectedData.push($(this).val());
            });
            return selectedData;
        }
    });

    if (location.hash) {
        $(location.hash).prop('checked', true).trigger('change');
    }
    $(window).on('hashchange', () => {
        location.reload();
        $(location.hash).prop('checked', true).trigger('change');
    });

    // const tabId = location.hash; //本番ではこちらを有効化してください
    const tabId = parent.location.hash; //デモ用(ご利用の際は削除してください)
    if (tabId) {
        $(tabId).click();
    }
});

この記事をシェアする

関連記事

全ての記事を見る

KONOCODEのメリット 無料会員登録