まずはサンプル
https://kackie.github.io/sort/
ポケモンです。すみません。
HTML内にスタイルとプログラムコードも記述してあります。
作った経緯
PCソフトウェアの紹介サイトで、ユーザが対応OSや保証期間など複数軸で絞り込みできるエリアがほしいということで、いろいろライブラリ等を探したりしてみたものの見つけられず、自分で作ることにしました。
おおまかな仕組み
主な処理は3つ。
- チェックボックス操作時、切り替えた内容に応じて表示を切り替える
- チェックボックス操作時、チェックのオンオフに応じてURLにパラメータを付与する
- ページ読み込み時、URLにパラメータが付いていたら内容に応じて表示を切り替える
1.チェックボックス操作時の動作
チェックの切り替えを行うと各カテゴリ毎に項目のオンオフを確認していき、配列を使って下記のような条件を作ります。
条件1 = カテゴリ1のチェック項目
条件2 = カテゴリ2のチェック項目
条件3 = カテゴリ3のチェック項目
切り替え対象の要素のうち、条件1にあてはまるもの かつ 条件2にあてはまるもの かつ 条件3にあてはまるもの を絞り込み、それ以外のものを非表示にします。
2.チェックに応じたパラメータの操作
1で作った条件の配列をもとに各カテゴリのどこにチェックが入っているかをテキストとして整形し、URLにパラメータとして付与します。
3.ページ読み込み時の動作
2で作られたパラメータを、ページ読み込み時に利用します。
URLにパラメータが付いていないときにはすべての要素を表示し、付いているときはその内容に応じて要素の表示非表示を切り替えます。
実装の肝の部分と解説
for(i=0;i<groupLength;i++){
var arr = [];
var filterArr = [];
if(sortControl.find('input[type="checkbox"][data-group="' + i + '"]:checked').length){
sortControl.find('input[type="checkbox"][data-group="' + i + '"]:checked').each(function(){
arr.push($(this).attr('id'));
filterArr.push('.' + $(this).attr('id'));
});
}
active[i] = arr;
if(filterArr.length){
allArr.push(filterArr);
}
param += (active[i].length) ? '?group' + i + '=' + active[i] : '';
}
カテゴリをグループ化するのにHTMLのdata属性を使用しました。
同一のdata属性内のチェックボックスのうちチェックがオンされているものを取得し、条件の作成に使っています。
if(allArr.length){
for(j=0;j<allArr.length;j++){
var filter = allArr[j].join(',');
showClass = showClass.filter(filter);
}
}
作られた条件の数を調べてその数の分だけ、すべての要素のうち条件1を満たすもの、かつ2を満たすもの...という絞り込みをかけていきます。
if($.isEmptyObject(param) !== true){
もし変数paramが空じゃなければ
$.isEmptyObject(変数)
→ 変数が空かどうかを調べる
history.pushState(null,null,param);
ページ遷移無しで、現在見ているページのURLの末尾にparamを付与し、それまで見ていたページを履歴に追加することができる。
if(location.search){
もしURLにパラメータがついていたら
やろうとしてできなかったこと・課題など
- カテゴリの数を手動で設定する必要がある
- groupLength = 3;
この部分。別にこれでも問題ないけどスマートではない気がする。
- groupLength = 3;
- チェックボックスにしか対応していない
- ラジオボタンやセレクトボックスは使えない。
今回の要件では必要なかったけれど、今後使い回すことを考えて書いても良かった。sortControl.find('input[type="checkbox"]').change
等の、条件がチェックボックスになっているところを書き換えたりif文を追加する必要がありそう。
- ラジオボタンやセレクトボックスは使えない。
- 連想配列に対して.lengthが使えない
- 知らなかった。
group[i]というラベルに対してチェックされているもののIDを格納した連想配列を作り、forループでURLに追加するパラメータを作ったり、表示切り替えの条件として使いたかった(ような気がする、忘れた)。
param += (active[i].length) ? '?group' + i + '=' + active[i] : '';
↑こんなふうにラベルを使わずパラメータを作成している。
- 知らなかった。
- パラメータの追加にlocation.searchは使えない
- 普通にページ遷移した。パラメータはあくまで外部リンク用なので、表示切り替え時にはリロードさせたくない。
パラメータの操作にはhistory.pushState()を使った。
- 普通にページ遷移した。パラメータはあくまで外部リンク用なので、表示切り替え時にはリロードさせたくない。
- 全体的に記述が冗長になってしまった。
-
var defCheck = '#' + defArr.join(',').replace(/,/g,',#');
defArr = '.' + defArr.join('|.').replace(/,/g,',.'); defArr = defArr.split('|');```<br> ↑読み込み時URLにパラメータがある場合それを取得し、activeClassに格納するためにテキストを変形させつつ配列にしている(なんだこりゃ)。<br> joinとreplaceを多用せずもっときれいに書けないもんかと思う。
-
まとめ
Qiita初投稿になります。皆さんはじめまして(遅
業務では基本的にHTMLを扱う人種なので、長めのプログラムを書いたのは本当に久々だったので、今後のために反省と覚え書きをしておこうと思い、書き始めた次第です。
簡単なサイト制作ではほぼ使わない配列やループ処理を実践できたのはよい経験でした。
表示非表示の切り替えに何かインタラクションを入れたかったのですが、非表示時の操作がわからず断念してしまいました(表示はstyleタグ内/*animation: show 0.3s ease 0s;*/
のコメントアウトを消せばいけます)。
Masonryを使って整列させようともしたのですがこちらもうまくいかず。
この辺りはうまく動かせるようにもっと色々試してみたいです。
あと似たような機能のライブラリあったら教えてください(切実)。