JavaScript
AWS
lambda
Vanilla.JS
APIGateway

Vanilla JSによる軽量tableソート

More than 1 year has passed since last update.

Webページのテーブルにソート機能が欲しいというのはよくある話で、JQueryあたりのライブラリを探して組み込むのが一般的だと思う。

ただ、組み込み先のページが10年以上前のprototype.jsを駆使した画面でJQueryと折り合いを付けるのが大変だったり、バンドルされたCSSの調整が面倒、といった問題が付きまとう。

そこで高速、かつ軽量で有名なフレームワークVanilla jsでの実装を試みた。


仕様



  • <table><thead><tbody>で構成されていることが条件

  • ページ内全ての上記条件に当てはまる<table>をソート対象にする

  • ヘッダー行のカラムtable > thead > thをクリックすると対象列の昇順でソートする

  • もう一回クリックすると降順でソートし、昇順、降順をクリックする度に切り替える

  • 数値変換可能文字列は数値として評価、その他は文字コードで評価しソートする


コード

<html>

<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title></title>
</head>
<body>
<table>
<thead>
<th>key</th>
<th>value</th>
</thead>
<tbody>
<tr>
<td>5</td>
<td>aaa</td>
</tr>
<tr>
<td>1</td>
<td>bbb</td>
</tr>
<tr>
<td>4</td>
<td>ccc</td>
</tr>
<tr>
<td>2</td>
<td>ddd</td>
</tr>
<tr>
<td>3</td>
<td>eee</td>
</tr>
</tbody>
</table>
<script type="text/javascript">

(function () {

function sort(tbody, compareFunction) {
var rows = tbody.children;
if(!rows || !rows[0] || rows.length == 1) return;
var size = rows.length;
var arr = [];
for(var i = 0; i < size; i++) arr.push(rows[i]);
arr.sort(compareFunction);
for(var i = size - 1; i > 0; i--) tbody.insertBefore(arr[i-1], arr[i]);
}
function numConvert(s) {
return s == Number(s) ? Number(s) : s;
}
function asc(idx) {
return function(a, b) {
var a_ = numConvert(a.children[idx].innerText);
var b_ = numConvert(b.children[idx].innerText);
return a_ > b_ ? 1 : -1;
};
}
function desc(idx) {
return function(a, b) {
var a_ = numConvert(a.children[idx].innerText);
var b_ = numConvert(b.children[idx].innerText);
return a_ < b_ ? 1 : -1;
};
}
function sortEvent(tbody, idx) {
var mode = true;
return function(e) {
if(mode) sort(tbody, asc(idx));
else sort(tbody, desc(idx));
mode = !mode;
};
}
var ts = document.getElementsByTagName('table');
for(var i = ts.length; i--; ) {
var ths = ts[i].tHead.getElementsByTagName('th');
for(var j = ths.length; j--; )
ths[j].addEventListener("click", sortEvent(ts[i].tBodies[0], j));
}
})();

</script>

</body>
</html>


動作確認

せっかくなのでQiitaページのテーブルをソートしてみた

やり方はギャル文字変換の記事を参照

ソート前

image

ソート後(key2)

image

OK!


所感

ブラウザ互換の問題がなくなりつつある今、Vanillaの選択肢はアリな気がしてきた


おまけ ES6版

書いてみたけどIEで動かないからお蔵入り

個人的にはブロックスコープとconst、letがかなり好き

アローはなくてもいいかな

{

const
sort = (tbody, compareFunction) => {
const rows = tbody.children;
if(!rows || !rows[0] || rows.length == 1) return;
const size = rows.length;
const arr = [];
for(let row of rows) arr.push(row);
arr.sort(compareFunction);
for(let i = size - 1; i > 0; i--) tbody.insertBefore(arr[i-1], arr[i]);
},
numConvert = (s) => (s == Number(s)) ? Number(s) : s,
getValue = (tr, idx) => tr.children[idx].innerText,
asc = (idx) => (a, b) => (numConvert(getValue(a, idx)) > numConvert(getValue(b, idx))) ? 1 : -1,
desc = (idx) => (a, b) => (numConvert(getValue(a, idx)) < numConvert(getValue(b, idx))) ? 1 : -1,
sortEvent = (tbody, idx) => {
let mode = true;
return (e) => {
mode ? sort(tbody, asc(idx)) : sort(tbody, desc(idx));
mode = !mode;
}
}
for(let table of document.getElementsByTagName('table')) {
const ths = table.tHead.getElementsByTagName('th');
for(let j = ths.length; j--; )
ths[j].addEventListener("click", sortEvent(table.tBodies[0], j));
}
}