【簡単】テーブルにソート機能を追加するList.jsの使い方【絞り込み/検索/ページネーション】
こんにちは、こじ(@kojiWebCode)です。
先日、List.jsを使った実装をする場面があったので、これを機にまとめておくことにしました。
本記事では、以下のようなお悩みを持つ方向けに解説します。
◆ List.jsでどんなことが出来るのかな…。
◆ 公式の説明を読んでもピンと来ない…。
◆ List.jsの基本的な使い方を知りたい。
「List.js」を利用すれば、テーブルやリストに対して、以下のような機能を追加できます。
- ソート機能
- 絞り込み(フィルタリング)機能
- 検索機能
- ページネーション
- データの追加・編集・削除(本記事では扱いません)
最初は、とっつきにくいかもしれませんが、慣れれば比較的簡単に導入することが出来ます。
基本的な使い方や注意すべきポイントをまとめていきますので、是非参考にしていただければ幸いです。
【準備】List.jsの使い方【ライブラリの読み込み】
「List.js」を利用するために、まずはライブラリを読み込みましょう。
ファイルをダウンロードする場合
赤枠で囲んだボタンをクリックしてファイルをダウンロードします。
ボタンをクリックした際に直にファイルの内容が表示される場合があります。
その場合は、ボタンの上で右クリックした後、「名前を付けてリンク先を保存」を選択してダウンロードしてください。
HTMLに下記コードを記述し、ファイルを読み込みます。
パスはファイルの配置位置によってご自身で変更してください。
<script src="./assets/js/list.min.js"></script>
CDNを利用する場合
CDNを利用する場合は、HTMLに下記コードを記述します。
<script src="//cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js"></script>
バージョンは変更になる可能性があるので、随時公式サイトを確認してください。
公式サイト上でのコードの記載位置は以下を参照してください。
【実装】List.jsで機能を追加する
実装機能の紹介と完成イメージ
See the Pen list.js⓪:全機能 by koji (@kojiWebCode) on CodePen.
このテーブルには、以下の機能を実装しています。
- ソート機能
- 絞り込み(フィルタリング)機能
- 検索機能
- ページネーション
これらの実装方法を、機能ごとに説明します。
ご自身でカスタマイズする際は、下記公式サイトも併せてご覧ください。
基本設定(必須設定)
「List.js」を使う上で、必須の設定があるので、まずそれを説明します。
以降説明する機能が動作しない場合は、この基本設定ができているかを確認してください。
必要な設定は以下の3点です。
- tableタグを囲う要素に対してid属性を付与する【HTML】
- テーブルデータを囲う要素に対して「list」クラスを付与する【HTML】
- JavaScriptを記述する
順番に説明します。
tableタグを囲う要素(ここではdivタグ)に対して、任意のid属性を付与します。ここでは、js-search-list
としました。
ここでの指定は、必ずid属性としてください。
<div class="search-list" id="js-search-list">
<!-- テーブル -->
<table class="search-list__table">
<!-- 略 -->
</table>
</div>
テーブルのデータを囲うタグに対して、list
クラスを付与します。
今回の場合は、tbodyタグに対して、以下のようにクラスを付与します。
<tbody class="list">
<!-- ここにテーブルデータが入ります -->
</tbody>
<ul class="list">
<li>リスト1</li>
<li>リスト2</li>
<li>リスト3</li>
</ul>
次にJavaScriptを記述します。まずは、List.jsのインスタンスを生成しましょう。
基本的にソート等のデータ操作を行うので、options内のvalueNamesの設定は必要になります。
valueNamesに記載する要素については、ソート機能で説明します。
const options = {
// ソートする対象を指定
valueNames: [
'title',
'genre',
'release',
'price',
],
};
// List.jsのインスタンス生成
const searchList = new List('js-search-list', options);
但し、ページネーションだけ実装する場合は、以下のようにvalueNamesの指定は不要です。
その代わりに、paginationに関する指定が必要になります。詳しくは、ページネーションをご覧ください。
const options = {
// 1ページに表示するデータ数
page: 3,
// ページネーション
pagination: {
paginationClass:'search-list__pagination-items',
innerWindow:1, // 現在のページの前後に表示するページャの数
outerWindow:2, // 最初と最後に表示するページャの数
},
};
// List.jsのインスタンス生成
const searchList = new List('js-search-list', options);
ここまでが(ほぼ)必須設定です。次からそれぞれの機能の実装方法を見ていきます。
ソート機能
【基本】ソート機能の追加方法
See the Pen list.js①:ソート機能_v1 by koji (@kojiWebCode) on CodePen.
ポイントは以下の3点です。
- ソートに必要なクラス名やデータ属性を付与する【HTML】
- optionsにソートする対象を指定する【JavaScript】
- ソート順を判りやすくする【CSS】
順番に説明します。
- ソートするには、
sort
クラスとdata-sort
というカスタムデータ属性をテーブルヘッダー(thタグ)に付けます。 - 各テーブルデータ(tdタグ)に
data-sort
に対応するクラス名をつけます。
<table class="search-list__table">
<thead>
<tr>
<!-- 'sort'クラスと'data-sort'というdata属性を付与する -->
<th class="sort" data-sort="title">タイトル</th>
<th class="sort" data-sort="genre">ジャンル</th>
<th class="sort" data-sort="price">価格</th>
<th class="sort" data-sort="release">発売年</th>
</tr>
</thead>
<tbody class="list">
<tr>
<!-- 各データに対してdata-sortに対応するクラス名を付与する -->
<td class="title">天空の彼方へ</td>
<td class="genre">小説</td>
<td class="price">¥780</td>
<td class="release">2018年</td>
</tr>
<tr>
<td class="title">HTML&CSS入門</td>
<td class="genre">専門書</td>
<td class="price">¥2,980</td>
<td class="release">2018年</td>
</tr>
<!-- 略(以下同様) -->
</tbody>
options内のvalueNamesにはソートする対象のクラス名を指定します。
const options = {
// ソートする対象を指定
valueNames: [
'title',
'genre',
'release',
'price',
],
};
// List.jsのインスタンス生成
const searchList = new List('js-search-list', options);
ここまで終えた段階で、ソート機能が有効化されるはずです。テーブルヘッダーをクリックし、対象の項目でソートされるか確認してみてください。
昇順、降順を切り替えたい場合は、テーブルヘッダーをもう一度クリックすれば他方へ切り替え可能です。
ここまでは、基本設定と同じですね!
「STEP. 2」までの段階でソート機能は有効化されていますが、“どの項目でソートされているか”、“昇順・降順のどちらなのか”が一見分かりづらいです。
そこで、「▲」「▼」をつけて、判別しやすくしましょう。
// テーブル
.search-list__table {
th {
&.sort {
cursor: pointer;
&.desc::after {
content: "▼";
margin-left: 10px;
font-size: 16px;
}
&.asc::after {
content: "▲";
margin-left: 10px;
font-size: 16px;
}
}
}
}
※それ以外のスタイルについては省略しています。
昇順の場合にはテーブルヘッダーにasc
クラスが、降順の場合にはdesc
クラスが自動的に付与されるので、それを利用しスタイルを当てます。
昇順には「▲」、降順には「▼」を擬似要素で表示させます。
これで、ソート項目、ソート順がわかりやすくなりました!
【応用】カンマ区切りの数字を正しくソートする
上記のサンプルでは、「価格」でソートすると意図した並び順にならないと思います。
これは、数字にカンマ区切りを入れていることが原因です。これを意図した順番で、ソートされるように修正しましょう。
手順は以下の通りです。
- カスタムデータ属性「data-price」をつける【HTML】
- valueNamesを修正する【JavaScript】
順番に説明します。
価格のテーブルデータに対して、「data-price」というカスタムデータ属性を付与し、その値にカンマ区切り等のない数字を入れます。
ここで入れる値が、ソート順を判断する値となります。
<tbody class="list">
<tr>
<td class="title">天空の彼方へ</td>
<td class="genre">小説</td>
<!-- data-priceを付与し値を入れる -->
<td class="price" data-price="780">¥780</td>
<td class="release">2018年</td>
</tr>
<tr>
<td class="title">HTML&CSS入門</td>
<td class="genre">専門書</td>
<td class="price" data-price="2980">¥2,980</td>
<td class="release">2018年</td>
</tr>
<!-- 略(以下同様) -->
</tbody>
JavaScriptのコードを修正します。
valueNames内を以下を参考に修正してください。
これによってprice
クラスを持つデータは、その値ではなく、data-priceの値によってソートされるようになります。
const options = {
valueNames: [
'title',
'genre',
'release',
{ name: 'price', attr: 'data-price' }, // 変更
],
};
修正後の動作は以下を参考にしてください。
See the Pen list.js①:ソート機能_v2 by koji (@kojiWebCode) on CodePen.
同様にして、他のデータに対しても、指定した文字列でソートさせることが可能です。
例えば、タイトルをローマ字表記でソートしたい場合は、data-title="Jiku no Tabibito"
のようにして、価格の時と同様にJSを修正すればOKです。
検索機能
【基本】検索機能の追加方法
See the Pen list.js②:検索機能_v1 by koji (@kojiWebCode) on CodePen.
検索機能の追加は簡単です。以下のコードを追加するだけです。
<input type="search" class="search" placeholder="検索">
ポイントは、クラスにsearchを付与することです。
【注意点】data属性がある場合はその値が検索の対象となる
先に説明したように、data属性を付与している場合は、指定した文字列がソートの対象となります。
検索の場合も同様で、data属性がある場合はその値が検索の対象となります。
例えば、タイトルをdata-title="Jiku no Tabibito"
のようにした場合には、「時空の旅人」と検索しても検索に引っかからず、「Jiku no Tabibito」と検索することで検索に引っかかります。
カンマ区切りの場合も同様に、data-price="2980"
と設定している場合、その値が検索の対象となります。
しかし、data属性を付与しない場合、「2,980」と検索しても検索結果に表示されません。
そもそもカンマ「,」を含むと検索の対象から外れてしまうようです。
以下は、タイトルにdata属性を付与、価格は付与しない場合の例です。上記の確認のためにお使いください。
See the Pen list.js②:検索機能_v2 by koji (@kojiWebCode) on CodePen.
ページネーション
【基本】ページネーションの追加方法
See the Pen list.js③:pagination by koji (@kojiWebCode) on CodePen.
ポイントは以下の2点です。
- ページネーション用のHTMLを用意する
- JavaScriptにページネーション用のコードを追記する
順番に説明します。
以下のようなHTMLを追記します。クラス名は自由につけてください。
<!-- ページネーション -->
<div class="search-list__pagination">
<ul class="search-list__pagination-items"></ul>
</div>
JSを追記します。STEP.1でつけたクラス名に合わせて適宜修正してください。
const options = {
valueNames: [
'title',
'genre',
'release',
{ name: 'price', attr: 'data-price' },
],
// 1ページ当たりの表示データ数
page: 3,
// ページネーション
pagination: {
paginationClass:'search-list__pagination-items',
innerWindow: 1, // 現在のページの前後に表示するページャの数
outerWindow: 2, // 最初と最後に表示するページャの数
},
};
以上で、ページネーションが追加できました。
ページネーションのスタイルはご自身で適宜調整してください。
絞り込み(フィルタリング)機能
1つの条件で絞り込みをする場合
See the Pen list.js④:フィルター×1 by koji (@kojiWebCode) on CodePen.
チェックを入れた条件によって、表示内容を絞り込む方法です。
上のサンプルは、「ジャンル」によって絞り込んでいます。
ポイントは以下の2点です。
- 絞り込みに使用するチェックボックスを用意する【HTML】
- 絞り込みに必要なJavaScriptコードを記述する
チェックボックスのinputタグに対して、カスタムデータ属性「data-filter」をつけます。ここでは、ラベルと同じ文字列を値として指定しています。
下記コードでつけているクラス名はすべて任意です。ご自由にお付けください。
<!-- フィルタリング -->
<dl class="search-list__filter-types">
<div class="search-list__filter-type">
<dt class="search-list__filter-name">ジャンル</dt>
<dd class="search-list__filter-data">
<label><input type="checkbox" class="check-box" data-filter="小説">小説</label>
</dd>
<dd class="search-list__filter-data">
<label><input type="checkbox" class="check-box" data-filter="専門書">専門書</label>
</dd>
<dd class="search-list__filter-data">
<label><input type="checkbox" class="check-box" data-filter="漫画">漫画</label>
</dd>
</div>
</dl>
JavaScriptに下記コードを追記します。
クラス名やdata属性に関しては、ご自身の環境に合わせて変更してください。
// チェックボックスの変更を監視
const checkboxes = document.getElementsByClassName('check-box');
for (const checkbox of checkboxes) {
checkbox.addEventListener('change', applyFilters);
}
function applyFilters() {
// 選択されたフィルタの値を取得
const filter = [];
for (const checkbox of checkboxes) {
if (checkbox.checked) {
const value = checkbox.getAttribute('data-filter');
filter.push(value);
}
}
// フィルタを適用してリストを更新
searchList.filter(function (item) {
const itemGenres = item.values().genre;
const filterMatched = filter.length === 0 || filter.some(filterItem => itemGenres.includes(filterItem));
return filterMatched;
});
}
以下に簡単な説明をします。
- 「1~5行目」は、チェックボックスの監視をしています。チェックの着脱がある度に、applyFilters関数を実行します。
- 「7~23行目」は、関数 applyFiltersの定義です。
- 「8~15行目」では、絞り込み用の配列filterを定義しておき、チェックがついたものを配列に追加します。
- 「19行目」の
const itemGenres = item.values().genre;
では、searchListのうちgenre
クラスを持つ要素をitemGenresとして定義しています。 - 「20行目」の
filterMatched
では、以下の場合にtrueを返します。- チェックボックスにチェックが1つも入っていない場合
- itemGenresがチェックした項目を含む(一致する)場合
- ③で、trueを返したデータのみ表示します。
2つの条件で絞り込みをする場合
See the Pen list.js④:フィルター×2 by koji (@kojiWebCode) on CodePen.
絞り込みの条件を2つにした場合です。
上のサンプルでは、「ジャンル」と「発売年」で絞り込んでいます。
今回の場合、以下を前提条件としています。
- ジャンル群で複数のチェックがついた場合、チェックがついたジャンルのデータをすべて表示する。
- 発売年の群で複数のチェックがついた場合、チェックがついた発売年のデータをすべて表示する。
- ジャンル群と発売年の群で同時にチェックがついた場合は、両群を満たすデータのみを表示する。
- チェックが1つもつかない場合は、すべて表示する。
つまり、最初の2つは「OR」、3つ目は「AND」です。
基本的なつくりは、フィルターが1つの場合と同じです。
チェックボックスのinputタグに対して、カスタムデータ属性「data-filter」をつけます。ここでは、ラベルと同じ文字列を値として指定しています。
<!-- フィルタリング -->
<dl class="search-list__filter-types">
<!-- ジャンル -->
<div class="search-list__filter-type">
<dt class="search-list__filter-name">ジャンル</dt>
<dd class="search-list__filter-data">
<label><input type="checkbox" class="check-box" data-filter="小説">小説</label>
</dd>
<dd class="search-list__filter-data">
<label><input type="checkbox" class="check-box" data-filter="専門書">専門書</label>
</dd>
<dd class="search-list__filter-data">
<label><input type="checkbox" class="check-box" data-filter="漫画">漫画</label>
</dd>
</div>
<!-- 発売年 -->
<div class="search-list__filter-type">
<dt class="search-list__filter-name">発売年</dt>
<dd class="search-list__filter-data">
<label><input type="checkbox" class="check-box" data-filter="2018年">2018</label>
</dd>
<dd class="search-list__filter-data">
<label><input type="checkbox" class="check-box" data-filter="2019年">2019</label>
</dd>
<dd class="search-list__filter-data">
<label><input type="checkbox" class="check-box" data-filter="2020年">2020</label>
</dd>
<dd class="search-list__filter-data">
<label><input type="checkbox" class="check-box" data-filter="2021年">2021</label>
</dd>
</div>
</dl>
基本的には、フィルターが1つの場合とやっていることは同じです。
クラス名やdata属性に関しては、ご自身の環境に合わせて変更してください。
// チェックボックスの変更を監視
const checkboxes = document.getElementsByClassName('check-box');
for (const checkbox of checkboxes) {
checkbox.addEventListener('change', applyFilters);
}
function applyFilters() {
// 選択されたフィルタの値を取得
const filters = {
genres: [],
years: []
};
for (const checkbox of checkboxes) {
if (checkbox.checked) {
const value = checkbox.getAttribute('data-filter');
if (value === '小説' || value === '専門書' || value === '漫画') {
filters.genres.push(value);
} else {
filters.years.push(value);
}
}
}
// フィルタを適用してリストを更新
searchList.filter(function (item) {
const itemGenres = item.values().genre;
const itemYears = item.values().release;
const genreFilterMatched = filters.genres.length === 0 || filters.genres.some(genre => itemGenres.includes(genre));
const yearFilterMatched = filters.years.length === 0 || filters.years.some(year => itemYears.includes(year));
return genreFilterMatched && yearFilterMatched;
});
}
リストをカスタマイズした例
以下は、リストでカスタマイズした例です。
See the Pen list.js⑤:リスト by koji (@kojiWebCode) on CodePen.
まとめ
本記事では、「List.js」の基本的な使い方とカスタマイズ例を紹介しました。
「List.js」を利用すれば、以下の機能を実装することができます。
- ソート機能
- 絞り込み(フィルタリング)機能
- 検索機能
- ページネーション
テーブルやリストのデータを操作する必要がある場合は、導入を検討してみるのも良いかと思います。
以上です。最後までお読みいただきありがとうございました。
「List.js」のカスタマイズでお悩みの方は、お気軽にご相談ください!
TwitterのDMからもご相談を承っております。