Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Vanilla JSによる軽量tableソート

More than 3 years have 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));
  }
}
bakenezumi
Scalaとか好きです
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away