【class属性でソート】JavaScriptを使ってクラス名だけでテーブルをソートする方法

<br>

::: note warn
需要無い方法だったら脱ぎます。

2023-02-15 追記
脱ぎました。
:::
::: note
2023-02-15 追記
この記事に頂いたコメントをお読みください。そちらの方がすごく使い勝手がいいです。
<b>コメントしていただきありがとうございます！！</b>
:::
# 目次
[1.やること](#1-やること)
[2.この方法を使うメリット・デメリット](#2-この方法を使うメリットデメリット)
[3.前提](#3-前提)
[4.ソートするテーブル](#4-ソートするテーブル)
[5.解説](#5-解説)
[6.終わりに](#6-終わりに)

# 1. やること
![1662235838268.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1311883/bf0beb30-0f67-c20c-d8be-1f72178c1a19.gif)
色が揃うの気持ち良すぎだろ

# 2. この方法を使うメリット・デメリット
### メリット
<font color="#ff0000"><b>・テーブルの中身が何であろうと、データを好きなようにソートできる
　→クラス名でソートするのでテーブルの中身は関係なしに自由にソートができるってワケ。</b></font>
・DOMをそのまま並び替えるだけなのでデータベースを通さない
　→爆速ソートができる
<font color="#ff0000"><b>・文字コードや数字の大小に影響されずにソートできる</b></font>


### デメリット
・ページネーションには対応できない
・たぶん小規模開発向き
<b>・ソートが一方通行（ソートを元に戻す処理を実装する必要あり）
<font color="#ff0000"><b>・実用的なのか分からない</font>


# 3. 前提
生のJavaScriptを使用しています。
Reactでも同じことができると思います。（この方法が必要かどうかはさておき）




# 4. ソートするテーブル

###  テーブル
英語長文の教材一覧を使っていきます。

::: note
こちらのテーブルを<font color="#ff0000"><b>「教材レベル（上から基礎→標準→応用→発展の順）」でソート</b></font>をします。
:::



![1662227159367.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1311883/8cb1ef4d-3fe8-dca0-3e4b-33dbc752fcc3.jpeg)

### テーブルのHTML
```html
<table>
    <thead>
        <tr>
            <th class="title-name">教材名</th>
            <th class="number-of-units">単元数</th>
            <th class="textboook-level" onclick="sortTableByLevel()">▼ 教材レベル</th>
        </tr>
    </thead>
<tbody id="textbook-list">
    <tr class="table-row 1" id="yatteokitai300">
        <td class="table__title">やっておきたい英語長文300</td>
        <td class="table__content-num">15</td>
        <td class="table__level level-1">基礎</td>
    </tr>
    <tr class="table-row 2" id="yetteokitai500">
        <td class="table__title">やっておきたい英語長文500</td>
        <td class="table__content-num">20</td>
        <td class="table__level level-2">標準</td>
    </tr>
    <tr class="table-row 3" id="yetteokitai700">
        <td class="table__title">やっておきたい英語長文700</td>
        <td class="table__content-num">15</td>
        <td class="table__level level-3">応用</td>
    </tr>
    <tr class="table-row 4" id="yetteokitai1000">
        <td class="table__title">やっておきたい英語長文1000</td>
        <td class="table__content-num">10</td>
        <td class="table__level level-4">発展</td>
    </tr>
    <tr class="table-row 1" id="s-lv-1">
        <td class="table__title">英語長文レベル別問題集①　超基礎編</td>
        <td class="table__content-num">12</td>
        <td class="table__level level-1">基礎</td>
    </tr>
    <tr class="table-row 1" id="s-lv-2">
        <td class="table__title">英語長文レベル別問題集②　基礎編</td>
        <td class="table__content-num">12</td>
        <td class="table__level level-1">基礎</td>
    </tr>
    <tr class="table-row 2" id="s-lv-3">
        <td class="table__title">英語長文レベル別問題集③　標準編</td>
        <td class="table__content-num">12</td>
        <td class="table__level level-2">標準</td>
    </tr>
    <tr class="table-row 3" id="s-lv-4">
        <td class="table__title">英語長文レベル別問題集④　中級編</td>
        <td class="table__content-num">12</td>
        <td class="table__level level-3">応用</td>
    </tr>
    <tr class="table-row 3" id="s-lv-5">
        <td class="table__title">英語長文レベル別問題集⑤　上級編</td>
        <td class="table__content-num">12</td>
        <td class="table__level level-3">応用</td>
    </tr>
    <tr class="table-row 4" id="s-lv-6">
        <td class="table__title">英語長文レベル別問題集⑥　難関編</td>
        <td class="table__content-num">10</td>
        <td class="table__level level-4">発展</td>
    </tr>
    <tr class="table-row 1" id="hypertraning-s1">
        <td class="table__title">英語長文ハイパートレーニング レベル1 超基礎編</td>
        <td class="table__content-num">12</td>
        <td class="table__level level-1">基礎</td>
    </tr>
    <tr class="table-row 2" id="hypertraning-s2">
        <td class="table__title">英語長文ハイパートレーニング レベル2 標準編</td>
        <td class="table__content-num">12</td>
        <td class="table__level level-2">標準</td>
    </tr>
    <tr class="table-row 3" id="hypertraning-s3">
        <td class="table__title">英語長文ハイパートレーニング レベル3 難関編</td>
        <td class="table__content-num">12</td>
        <td class="table__level level-3">応用</td>
    </tr>
    <tr class="table-row 1" id="kawai-basic">
        <td class="table__title">マーク式基礎問題集 英語 基礎</td>
        <td class="table__content-num">10</td>
        <td class="table__level level-1">基礎</td>
    </tr>
    <tr class="table-row 3" id="kawai-application">
        <td class="table__title">マーク式基礎問題集 英語 応用</td>
        <td class="table__content-num">10</td>
        <td class="table__level level-3">応用</td>
    </tr>
</tbody>
</table>
```
それでは、このテーブル及びHTMLを使用して手順を説明していきます。


# 5. 解説

あらかじめ、tr要素のクラス名に付けておいた1~4の数字を使ってソートしていきます。

::: note info
各数字は「1: 基礎　2: 標準　3: 応用　4: 発展」に対応しています
:::
↓ 上記のコードで言うところのコレです（緑色のとこ）
```diff_html
<tbody id="textbook-list">
    // classに付いてる数字をソートに使用します。 
+   <tr class="table-row 1" id="yatteokitai300">                      // 1
        <td class="table__title">やっておきたい英語長文300</td>
        <td class="table__content-num">15</td>
        <td class="table__level level-1">基礎</td>
    </tr>
+       <tr class="table-row 2" id="yetteokitai500">                  // 2
        <td class="table__title">やっておきたい英語長文500</td>
        <td class="table__content-num">20</td>
        <td class="table__level level-2">標準</td>
    </tr>
+   <tr class="table-row 3" id="yetteokitai700">                      // 3
        <td class="table__title">やっておきたい英語長文700</td>
        <td class="table__content-num">15</td>
        <td class="table__level level-3">応用</td>
    </tr>
+   <tr class="table-row 4" id="yetteokitai1000">                     // 4
        <td class="table__title">やっておきたい英語長文1000</td>
        <td class="table__content-num">10</td>
        <td class="table__level level-4">発展</td>
    </tr>
+   <tr class="table-row 1" id="s-lv-1">                              // 1
        <td class="table__title">英語長文レベル別問題集①　超基礎編</td>
        <td class="table__content-num">12</td>

                        ・
                        ・
                        ・
```
<br>
<b>この数字はテーブルを生成する際に付与しました。</b>

::: note
どう付与する？
今回はデータベースに数字で保存している「教材レベル」をそのまま<b>classList.add()でクラス名に付与</b>しました。
:::

## ソートをする（図解）
どうやってクラス名だけでソートするかを図解します。

### ①ソート前のtr要素をすべて取得する
今回は getElementsByClassName('table-row') で取得しました。
![1662233201834.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1311883/7c2496f7-e05d-a42c-af86-3c6dd900526a.jpeg)


### ②tr要素をクラス名ごとに配列に入れる
クラス名に付いてる1,2,3,4の数字ごとに分けていきます。
![1662233225675.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1311883/ae57f1ad-1b4a-7453-436e-e67c95c27e73.jpeg)


### ③分けた配列を一つの配列にし、①で取得したテーブルに入れる
クラス名で分けたtr要素を一つの配列にします。
![1662236445826.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1311883/7421cd17-345e-a298-09b7-c0ad81065d65.jpeg)

これで完成です。


### それを実装したコードがこちら
```javascript
//   難易度でのソート機能
function sortTableByLevel() {
    // テーブルを取得
  const table = document.getElementById("textbook-list");

    // テーブル内のtr要素を全て取得する
  const tr_elements = table.getElementsByClassName("table-row");

    // Array.prototype.slice.callで配列にする。
  const before_sorted_array = Array.prototype.slice.call(tr_elements);

  let array1 = [];  // 基礎（class名に 1 が付いたtr要素）を入れる配列
  let array2 = [];  // 標準（class名に 2 が付いたtr要素）を入れる配列
  let array3 = [];  // 応用（class名に 3 が付いたtr要素）を入れる配列
  let array4 = [];  // 発展（class名に 4 が付いたtr要素）を入れる配列

    // 一つずつtr要素を取り出して、クラス名に1,2,3,4のどれが含まれているかで条件分岐
  before_sorted_array.map((item) => {
    if (item.classList.contains("1")) {
      array1.push(item);
    } else if (item.classList.contains("2")) {
      array2.push(item);
    } else if (item.classList.contains("3")) {
      array3.push(item);
    } else if (item.classList.contains("4")) {
      array4.push(item);
    }
  });

    // array1にarray2, array3, array4の順で合体させてソートが終了
  const after_sorted_array = array1.concat(array2, array3, array4);

    // ソート前のテーブルをすべて削除してテーブルを空っぽにする
  while (table.firstChild) {
    table.removeChild(table.firstChild);
  }
    // 空っぽのテーブルにソートしたtr要素をテーブルにぶち込む
  after_sorted_array.forEach((item) => {
    table.appendChild(item);
  });

}
```

::: note warn
もう一度ソートをクリックしても元には戻りません。
元の並びを変数に入れたりなんなりしたら元に戻すことも実装できそうです。
:::
終わりです。

<font color="#ff0000"><b>class名でソートをすれば、どんなデータでも簡単(？)にお好みのソートができます。</b></font>
クラス名でなくてもnameやidでも同じことができそうですし、if文の分岐を工夫すれば、<b>クラス名は数字じゃなくても実装できそう</b>です。
# 6. 終わりに
図解にある after_sorted_array って変数名おかしい。
array_after_sort（ソート後の配列）の方がしっくりきますねー。おーん。