【jQuery】複数の選択項目での絞り込み処理 + 遷移元からのアンカー付リンク ( hashタグありリンク ) で遷移後にタブ切り替え
[ ID : 11623 ]
                     
                    
                                            実装目安
                                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();
    }
});
ローカル環境にコードを移設した際に動作しない場合はこちら。(トラブルシューティングページへ)
 
                                 
                                 
                                 
                                                                                     
                                                                                     
                                                                                     
            