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

更新日
2017.07.05
作成日
2017.02.15

v-if / v-show / 算出プロパティを使って条件によって要素や属性などの内容を切り替えます。

表示・非表示の条件を指定するには v-showv-if ディレクティブを使用します。

v-show と v-if の違い

2つの違いは、v-show は CSS で display:none を付けて単純に画面上でのみ非表示にしているのに対して v-if は DOM レベルで削除されます。表示・非表示を何度も切り替えるような場合は v-show を使う方がパフォーマンス的には良いです。

逆に v-show は見えて無くても内側はずっとリアクティブに動いてるので、切り替えの頻度が低いわりには内側のリアクティブなデータが多かったり特定のオブジェクトを持っていないと内側でエラーが出るなど非表示中に内側の処理をさせたくない場合は v-if を使うといいです。

また key が設定されていて keep-alive を使っていないコンポーネントに対して使用した場合、v-if は切り替わる毎に created などのライフサイクルが発生します。

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

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

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

v-show の書き方は以下のようになります。

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

条件式の部分には JavaScript の if 文のカッコ内で書くような式を書きます。真偽値を表すデータを渡しても良いです。 v-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="inputprice" size="5"> 円以下の商品を表示
<!-- ボタンを押すと price が更新されて同時に結果も更新される -->
<button @click="price = inputprice">click!</button>

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

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

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

スタイルやクラスにも条件を付けたい

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

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

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

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

算出プロパティを使う

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

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

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

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

<ul>
    <li v-for="val in matchList">
        {{ val.name }} {{ val.price }} 円
    </li>
    <li v-if="!matchList.length">
        該当する商品はありません
    </li>
</ul>
<input v-model="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 と使い分けていくと良さそうです。次回はいよいよコンポーネントについて勉強したいと思います。