Vue 2 | 条件分岐と算出プロパティ

条件に応じて要素や属性などの内容を表示、非表示に切り替えるには、v-showv-ifディレクティブ属性を使用する。

  • Vue 2.5.4

v-showとv-ifの違い

両者の違いは、v-showはCSSのdisplay: noneで単純に画面上だけ非表示にするのに対し、v-ifはDOMレベルで存在を削除する点である。

表示と非表示を何度も切り替える場合は、v-showを使うほうが性能面でよい。ただし、v-showは見えていなくても内部では状態を監視し続けている。

内部データが多い場合や、特定のオブジェクトを持っていないとエラーが発生する場合など、単に非表示になっている状態で処理を走らせたくない場合は、v-ifを使うとよい。

一覧に特定条件を満たすデータだけを表示する

次のデータを使い、入力した数値以下の商品だけを表示したいとする。

new Vue({
  el: '#app',
  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には、入力値を数値に変換する修飾子(.number)も用意されている。

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

<ul>
    <li v-for="val in list" v-show="!price || val.price <= price">
        {{ val.name }} <span v-bind:style="{color: val.price <= 200 ? 'red' : 'blue'}">{{ val.price }}円</span>
    </li>
</ul>

コード実行

上の例では、価格が200円以下であれば赤色になるようにした。styleclassは複数の値を持つことがあるため、v-bindではオブジェクト形式でそれぞれに条件を付けることができる。v-bindを使わず通常どおりに書いたstyleclassがある場合は、マージされた結果が表示される。

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

colorValueには、式や真偽値を持つデータを書く。オブジェクトや加工済みの文字列データを渡してもよい。

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

算出プロパティを使う

ところで、ここで同時に「X件見つかりました」や「何も見つかりません」といった表示もしたい場合、最終的に検索されたデータ数をどう取得すればよいだろうか。公式ガイドを見ると「算出プロパティ」というものがある。データを検索するときに処理できる機能なので、これを使えば実現できそうである。

算出プロパティは、何らかの処理をした結果をデータ値として返すことができる。上の例と異なる点は、v-forに渡された時点ですでに条件を満たしたものだけが配列になっていることである。文字列を付け加えたり、不要なものを取り除いたり、現在持っているデータから新しいデータを作ったりと、さまざまなことが可能である。methodsと同じように、computedというオプションに関数を定義する。関数として定義するが、使い方は名前のとおりプロパティとして使う。

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') // テストなので実行時にログを残す。
       // filterを使って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を入れてみたところ、一度だけ実行された。算出プロパティは、その中で使用しているデータに変化があるまでキャッシュされるようである。便利ではないか。つまり、methodを使うより利点があるということである。

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

算出キャッシュ vs メソッド

つまり、依存しているデータに変化があると算出プロパティも同期してしまうため、変化してもすぐに表示を更新したくない場合や、何らかの条件で新しいデータを作りたい場合には、別の記事で扱う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との使い分けが分かるようになるとよいだろう。次はいよいよコンポーネントについて説明する。