Vue.jsのv-forでの並び順を指定したキーの値順にしたり、昇順、降順を切り替えたりする

公開日:2018/11/22 更新日:2018/11/22
Vue.jsのv-forでの並び順を指定したキーの値順にしたり、昇順、降順を切り替えたりするのサムネイル

はじめに

Vue.jsで使用できるv-forは簡単にリストレンダリングできとても便利です。ただ、レンダリングの順番を指定したキーで並べ替えたり、昇順と降順を切り替えるにはcomputedやmethodを用意する必要があります。ここではアルファベット順や数値順で並べ替えるためのフィルターやメソッドをについてメモします。

前提と環境

ここでのVue.jsアプリは、Vue CLIのcreateコマンドによって作成したデフォルトの状態です。Vue.jsアプリの作成手順は、Windows10(WSL使用)でVue.jsアプリを作成するまでの手順にまとめています。

  • Vue.jsアプリはWindows10 + WSL + Ubuntu上で動作
  • Node.js、Vue CLI(3系)はインストール済とする
  • Vue.jsアプリはVue CLIで作成済。(router、scssなどの機能を指定して作成)

Vue.jsアプリフォルダのツリー構造は以下のようになっています。以降の説明では以下のHome.vueだけをいじって説明します。

├── babel.config.js
├── node_modules
├── package.json
├── package-lock.json
├── public
├── README.md
└── src
    ├── App.vue
    ├── assets
    │   └── logo.png
    ├── components
    │   └── HelloWorld.vue
    ├── main.js
    ├── router.js
    └── views
        ├── About.vue
        └── Home.vue

また、ここでは以下のオブジェクトをv-forでリストレンダリングする想定で説明します。

items:[
          {
            id: 1,
            name: 'aaa',
            email: 'AAA@test.local',
            message: 'This is AAA message',
            amount: 80,
          },
          {
            id: 2,
            name: 'BBB',
            email: 'BBB@test.local',
            message: 'This is BBB message',
            amount: 40,
          },
          {
            id: 3,
            name: 'CCC',
            email: 'CCC@test.local',
            message: 'This is CCC message',
            amount: 100,
          },
        ]

要素の順番通りにレンダリングする

まずはデフォルトの状態でレンダリングするために以下のようなコードを使います。以下は、Home.vueです。

Home.vue
<template>
  <div class="home container">
    <section style="margin-bottom: 20px;" v-for="item in items" v-bind:key="item.id">
      <div class="card">
        <header class="card-header">
          <p class="card-header-title">{{ item.name }} - {{ item.amount }}</p>
          <a href="#" class="card-header-icon" aria-label="more options">
            <span class="icon">
              <i class="fas fa-angle-down" aria-hidden="true"></i>
            </span>
          </a>
        </header>
        <div class="card-content">
          <div class="content">{{ item.message }}
            <a href="#">{{ item.email }}</a>
          </div>
        </div>
      </div>
    </section>
  </div>
</template>
<script>
export default {
  name: 'home',
  data() {
    return {
        items:[
          {
            id: 1,
            name: 'aaa',
            email: 'AAA@test.local',
            message: 'This is AAA message',
            amount: 80,
          },
          {
            id: 2,
            name: 'BBB',
            email: 'BBB@test.local',
            message: 'This is BBB message',
            amount: 40,
          },
          {
            id: 3,
            name: 'CCC',
            email: 'CCC@test.local',
            message: 'This is CCC message',
            amount: 100,
          },
        ],
    }
  },
}
</script>

ブラウザからアクセスしてみると、以下のような表示になります。

default-order-1024x502.png

続いて、これを配列の要素を逆順から並べてみます。

要素の後ろからリストレンダリングする

配列の後ろからリストレンダリングするには、computedで配列をの順番を入れ替えて、その配列をv-forに渡します。具体的には、以下のようにreverseItems()という関数をcomputedに用意し、それをv-forに渡します。他は全く一緒です。

Home.vue
<template>
  <div class="home container">
    <section style="margin-bottom: 20px;" v-for="item in reverseItems" v-bind:key="item.id">
      <div class="card">
        <header class="card-header">
          <p class="card-header-title">{{ item.name }} - {{ item.amount }}</p>
          <a href="#" class="card-header-icon" aria-label="more options">
            <span class="icon">
              <i class="fas fa-angle-down" aria-hidden="true"></i>
            </span>
          </a>
        </header>
        <div class="card-content">
          <div class="content">{{ item.message }}
            <a href="#">{{ item.email }}</a>
          </div>
        </div>
      </div>
    </section>
  </div>
</template>
<script>
export default {
  name: 'home',
  data() {
    return {
        items:[
          {
            id: 1,
            name: 'aaa',
            email: 'AAA@test.local',
            message: 'This is AAA message',
            amount: 80,
          },
          {
            id: 2,
            name: 'BBB',
            email: 'BBB@test.local',
            message: 'This is BBB message',
            amount: 40,
          },
          {
            id: 3,
            name: 'CCC',
            email: 'CCC@test.local',
            message: 'This is CCC message',
            amount: 100,
          },
        ],
    }
  },
  computed: {
    // 配列の要素順番を逆順にする
    reverseItems() {
        return this.items.slice().reverse();
    },
  }
}
</script>

なお、上記のreverseItems()の中のitemsdataの中のitemsです。もし各自で使う場合は、ここをそれぞれのオブジェクト名に置き換えてください。

以下のような表示になります。配列の後ろから順番に表示されていることがわかります。

reversed-order-1024x512.png

次はitemsの中のamountの昇順、降順で表示します。

指定したキーの数値でリストレンダリングする

例としてitemsの中のamountで並べ替えて表示してみます。同じくcomputedで以下のようにsortedItemsByAmount()という関数を用意し、それをv-forに渡します。

Home.vue
<template>
  <div class="home container">
<section style="margin-bottom: 20px;" v-for="item in sortedItemsByAmount" v-bind:key="item.id">
(途中省略。前節のコードと全く同じです。)
computed: {
    // amountで並べ替え
     sortedItemsByAmount(){
        return this.items.sort((a, b) => {
          return (a.amount < b.amount) ? -1 : (a.amount > b.amount) ? 1 : 0;
        });;
    }
  }

上記のsortedItemsByAmount()の中のitemsdataの中のitemsamountitemsのキーです。各自で使う場合は、それぞれのオブジェクト名、キー名に置き換えてください。

以下のような表示になります。amountの昇順で表示されます。

sortedbyamount1-1024x499.png

もしamountの降順で表示したい場合は、以下のようにsortedItemsByAmount()の中の数値の-11を入れ替えます。

sortedItemsByAmount(){
        return this.items.sort((a, b) => {
          return (a.amount < b.amount) ? 1 : (a.amount > b.amount) ? -1 : 0; // -1と1を入れ替え
        });;
    }

なぜこれで昇順、降順が入れ替わるか、sort関数については以下の参考サイト様がわかりやすいです。

www.ajaxtower.jp

sortメソッドは対象のArrayクラスのオブジェクトの各要素をアルファベット順に並べ替えます。

次はアルファベット順番に並べる場合について説明します。

アルファベット順でリストレンダリングする

例としてitemsの中のnameで並べ替えて表示してみます。computedsortedItemsByName()という関数を用意し、それをv-forに渡します。なお、以下は大文字、小文字を区別せずに並べ替える場合です。

Home.vue
<template>
  <div class="home container">
<section style="margin-bottom: 20px;" v-for="item in sortedItemsByName" v-bind:key="item.id">
(途中省略。前節のコードと全く同じです。)
computed: {
    sortedItemsByName(){
        return this.items.sort((a, b) => {
          let textA = a.name.toUpperCase();
          let textB = b.name.toUpperCase();
          return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;
        });;
    },
  }

上記のsortedItemsByAmount()の中のitemsdataの中のitemsnameitemsのキーです。各自で使う場合は、それぞれのオブジェクト名、キー名に置き換えてください。

ここの例では、表示は冒頭に載せた場合の配列の要素順と同じになるので省略します。もしアルファベットで降順にしたい場合(Z→A)は、前節と同じようにsortedItemsByName()の中の数値の-11を入れ替えます。

sortedItemsByName(){
        return this.items.sort((a, b) => {
          let textA = a.name.toUpperCase();
          let textB = b.name.toUpperCase();
          return (textA < textB) ? 1 : (textA > textB) ? -1 : 0; // -1と1を入れ替え
        });;
    }

もし大文字と小文字を区別して並べ替えたい場合は、すでに述べた指定したキーの数値で並べ替える方法をそのまま使えば実現できます。昇順では小文字から大文字、降順では大文字から小文字で並べ替えされます。具体的には、以下のようにsortedItemsByAmount()のキー名をamountからnameに変更するだけでOKです。

sortedItemsByAmountName(){
        return this.items.sort((a, b) => {
          return (a.name < b.name) ? -1 : (a.name > b.name) ? 1 : 0;
        });;
    }

最後に、昇順と降順を切り替えるためのボタンを実装してみます。

昇順、降順を切り替えるためのボタンを実装する

すでに述べたように、昇順と降順を切り替えるには、単純にcomputedに用意した各関数内にあるsort内の1-1を切り替えればOKです。したがって、例えば、sortOrderという値と以下のようなメソッドを用意します。

data() {
 return {
   items:[... 省略...],
   sortOrder: 1
 }
},
(途中省略)
methods: {
   changeOrder(){
      this.sortOrder = this.sortOrder > 0 ? -1 : 1;
   },
  }

さらに、これまでに説明したsortedItemsByAmount() sortedItemsByName()の中の数値の1this.sortOrderに変更します。例えばsortedItemsByAmount()の場合は以下のようになります。

sortedItemsByAmount(){
        return this.items.sort((a, b) => {
          return (a.amount < b.amount) ? -this.sortOrder : (a.amount > b.amount) ? this.sortOrder : 0;
        });;
    },

あとはクリックすることで上記のchangeOrderを呼び出すボタンを例えば以下のように用意します。

<button class="button" @click="changeOrder">順番切り替え</button>

ボタンをクリックしてみると、昇順と降順が入れ替わることを確認できると思います。もちろん、ボタンではなくリンクをクリックした場合などにchangeOrderを呼び出しても同じです。

まとめ

Vue.jsのv-forでのリストレンダリングの順番を操作する方法をまとめました。

関連記事

開発アプリ

nanolog.app

毎日の小さな出来事をなんでも記録して、ログとして残すためのライフログアプリです。