概要
複数の選択項目での絞り込み処理と遷移元から所定のアンカーリンク(ハッシュタグを付与された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();
}
});
ローカル環境にコードを移設した際に動作しない場合はこちら。(トラブルシューティングページへ)