Vue.js で条件分岐 and 算出プロパティ

最終更新日
2017.11.17

条件によって要素や属性などの内容、表示/非表示を切り替えるには、v-showv-if ディレクティブ、算出プロパティを使用します。

  • Vue 2.5.4

v-show と v-if の違い

2つの違いは、v-show は CSS で display:none を付けて単純に画面上でのみ非表示にしているのに対して v-ifDOM レベルで存在を削除されます。

表示・非表示を何度も切り替えるような場合は v-show を使う方がパフォーマンス的には良いです。ただし v-show は見えて無くても内側はずっと状態を監視しています。

内側のデータが多かったり特定のオブジェクトを持っていないとエラーが出るなど非表示中に処理をさせたくない場合は v-if を使うといいです。

リストの特定の条件のデータだけ表示

以下のデータを使って、入力した数値以下の商品だけを表示するようにしたいと思います。

new Vue({
  el: '#app1',
  data: {
    price: 300,
    inputprice: 200,
    list: [{
      name: 'とまと',
      price: '100'
    }, {
      name: 'れたす',
      price: '200'
    }, {
      name: 'きゅうり',
      price: '300'
    }]
  }
})

書き方は v-showv-if も同じで以下のようになります。

<li v-for="val in list" v-show="条件式">条件を満たしたら表示される</li>

条件式の部分には JavaScript の if 文のカッコ内で書くような式を書きます。メソッド名でも真偽値を表すデータを渡してもいい。

<ul>
 <!-- val.price が入力された price よりも小さければ表示 -->
 <li v-for="val in list" v-show="val.price <= price">
  {{ val.name }} {{ val.price }} 円
 </li>
</ul>
<input v-model.number="inputprice" size="5"> 円以下の商品を表示
<!-- ボタンを押すと price が更新されて同時に結果も更新される -->
<button @click="price = inputprice">click!</button>

v-model に紐付けている inputprice の値を使うとリアルタイムに検索されますが、今回はボタンを押したタイミングで検索させたかったので price というデータに入力値を代入してそれを条件に使うようにしました。

数字を入力するとそれ以下の値段の商品だけ表示されましたね(•ө•)ノ 実際には数字以外が入力され場合の処理とかも必要ですがリアルタイムフィルタリングとか簡単に出来る機能があったりするのでしょうか?またあとで調べます。

ちなみに、v-model には入力値を数値に変換させるというような 修飾子もいくつか用意されています。

スタイルやクラスに条件を付ける

上の例ではついでに値段が200円以下なら赤くするようにしました。 styleclass は値が複数になる事があるため v-bind ではオブジェクト形式でそれぞれに条件を付ける事ができます。v-bind を付けずに普通に書いている styleclass があった場合はマージされた結果が表示されます。

<span :style="{ color: colorState }">テキスト</span>
<span :class="{ active: price < 200 }">テキスト</span>

styleState には式や真偽値、値になるデータを書きます。オブジェクトや加工済みの文字列データを渡してしまってもいいです。

<span :style="styleState">テキスト</span>

算出プロパティを使う

さて、ここで同時に「X件見つかりました」や「何も見つかりませんでした」みたいな表示もしたいのですが、最終的にヒットした数値をどうやって取得したらいいのでしょうか?公式ガイドを見ると算出プロパティと言うものがあります。データを取得する時に処理が出来る機能みたいなのでこれを使えば出来そうです。

算出プロパティは何か処理をした結果をデータとして返せます。上の例と違うのは v-for渡された時点で既に条件を満たしたものだけの配列になっているという事です。文字を付け加えたり、不要なものを取り除いたり、今持っているデータから新しいデータを作ったり色々出来ます。 methods と同じように computed というオプションに登録します。

new Vue({
  el: '#app2',
  data: {
    price: 300,
    inputprice: 200,
    list: [{
      name: 'とまと',
      price: '100'
    }, {
      name: 'れたす',
      price: '200'
    }, {
      name: 'きゅうり',
      price: '300'
    }]
  },
  computed: {
    matchList: function() {
      console.log('matchList') // テストなので実行した時にログを残す
      // フィルターを使って price より小さいものだけの配列を作って返す
      return this.list.filter(function(val) {
        return val.price <= this.price
      }, this)
    }
  }
})

matchList という名前で簡単な算出プロパティを作ってみました。

<ul>
    <li v-for="val in matchList">
        {{ val.name }} {{ val.price }} 円
    </li>
    <li v-if="!matchList.length">
        該当する商品はありません
    </li>
</ul>
<input v-model.number="inputprice" size="5"> 円以下の商品を表示
<button @click="price = inputprice">click!</button>
{{ matchList.length }} 個見つかりました

算出プロパティで先に処理をして結果の length を見ればヒット数がわかりますね!

でも matchList を3箇所も使ってるのでその度に関数が実行されるのかなーと不安に思って console.log を入れてみたら1回しか実行されてません。算出プロパティはその中で使用しているデータに変化があるまではキャッシュされるみたいです。有能か。でも大丈夫 method さんにも得意な事があるからね。

算出プロパティは依存関係にもとづきキャッシュされるという違いがあります。

算出プロパティ vs メソッド

逆に言えば依存データに変化があれば算出プロパティも同期してしまうので、変化してもすぐに表示を更新させたくなかったり任意の条件で新しいデータを作成したいっていう時には method や別の記事で書いている watch を使うのが良いです。

v-if / v-else-if / v-else で複数の条件を設定

v-if と組み合わせて v-else-if、v-else というようなディレクティブも使用できます。必ず条件要素の直後に置くようにして使用します。

<div v-if="条件A">条件A</div>
<div v-else-if="条件B">条件B</div>
<div v-else>一致しなかった</div>

おわりに

アプリを作るには条件分岐は必要不可欠ですね。算出プロパティは凄く便利です!状況に応じて method と使い分けていくと良さそうです。次回はいよいよコンポーネントについて勉強したいと思います。