2018/01/15

[Vue.js]タイトルラベルクリックでソート可能なテーブルをつくる

なんらかのサービスでテーブル要素を使うとき、多くの場合はタイトルラベルをクリックしたらテーブル内のデータがソートされるような機能がある。

ということで、シンプルな構成でソート可能なテーブルをVue.jsをつかってつくる。
vueのバージョンは2系(2.5で動作確認)を使う。

ソート可能なテーブルをつくる

<main id="app">
  <table>
    <thead>
      <tr>
        <th
          :class="sortedClass('id')"
          @click="sortBy('id')"
        >
          ID
        </th>
        <th
          :class="sortedClass('name')"
          @click="sortBy('name')"
        >
          Name
        </th>
        <th
          :class="sortedClass('age')"
          @click="sortBy('age')"
        >
          Age
        </th>
      </tr>
    </thead>
    <tbody>
      <tr
        v-for="item in sortedItems"
        :key="item.id"
      >
        <td>{{ item.id }}</td>
        <td>{{ item.name }}</td>
        <td>{{ item.age }}</td>
      </tr>
    </tbody>
  </table>
</main>
// import vue@2.5
new Vue({
  el: '#app',
  data () {
    return {
      sort: {
        key: '',
        isAsc: false
      },
      items: [
        { id: 1, name: 'taro', age: 20 },
        { id: 2, name: 'jiro', age: 15 },
        { id: 3, name: 'saburo', age: 18 },
        { id: 4, name: 'shiro', age: 14 },
      ]
    }
  },
  computed: {
    sortedItems () {
      const list = this.items.slice();  // ソート時でdataの順序を書き換えないため
      if (!!this.sort.key) {
        list.sort((a, b) => {
          a = a[this.sort.key]
          b = b[this.sort.key]

          return (a === b ? 0 : a > b ? 1 : -1) * (this.sort.isAsc ? 1 : -1)
        });
      }
      
      return list;
    }
  },
  methods: {
    sortedClass (key) {
      return this.sort.key === key ? `sorted ${this.sort.isAsc ? 'asc' : 'desc' }` : '';
    },
    sortBy (key) {
      this.sort.isAsc = this.sort.key === key ? !this.sort.isAsc : false;
      this.sort.key = key;
    }
  }
});
table {
  th {
    cursor: pointer;
    
    &.sorted {
      &.asc::after {
        display: inline-block;
        content: '▼';
      }
      &.desc::after {
        display: inline-block;
        content: '▲';
      }
    }
  }
}
th要素にクリックイベントを登録し、sortBy(key)でソートするキーと順番を設定する。
するとcomputed#sortedItemsが再計算され、データがソートされるという仕組み。

Array.prototype.sortはミュータブルなメソッドなので、もとのdata#itemsの並び順を変えないためArray.prototype.sliceで配列をコピーしてからソートしている。

普段Array.sort((a, b) => a - b)のように実装すると思うのだが、その結果に昇順なら*1、降順なら*-1をして並び順をかえている。


methods#sertedClassは、ソートされているラベルに▲/▼を表示するために使っている。
ラベルがクリックされたらth.sorted.ascth.sorted.descのようにclassを設定し、疑似要素::afterで▲/▼を表示している。



今回紹介したソート可能なテーブルを、より汎用的なコンポーネントにする場合はちょっと手間がかかるのでUIライブラリなどの利用を検討されたほうが良いだろう。
(もしくはElementUIを参考にするとか)



以上

written by @bc_rikko

0 件のコメント :

コメントを投稿