Vue.jsのv-if、v-showの違いについて


この記事を書こうと思ったきっかけ

先月Vue.jsを使いWebアプリケーションを使う機会があったのですが
オブジェクトのデータを表示するかしないかの判定をv-ifとv-showのどちらを使用してやるかを悩みながら実装していたのですが
実装していく中で違いが明確にわかるパターンのコードを見つけたので議事録的な意味を含めて記事にまとめておこうと思います

ベースにするコード

HelloWorld.vue

<template>
  <div class="hello">
    <div v-for="box in boxs" :key="box.name" :style="[setSize(box)]">
      {{ box.name }}
    </div>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      boxs: [
        {name: 'box1', width: 100, height: 50, color: 'red'},
        {name: 'box2', width: 100, height: 100, color: 'blue'},
        {name: 'box3', width: 100, height: 150, color: 'green'}
      ]
    }
  },
  methods: {
    setSize (box) {
      console.log('methods in')
      const height = box.width + box.height
      return {
        width: box.width + '%',
        height: height + 'px',
        backgroundColor: box.color
      }
    }
  }
}
</script>

boxsのオブジェクトを配置し、設定しているnameの表示
styleはheightのみ定義してあるwidthとheightを足した物を設定してある
また、メソッド内に入る事を確認するためにconsole.logでログを出力している
表示される画面は以下の通り

ログ

3つのboxがあるので3回ログが表示される

ここでboxsのstyle要素を消していき、表示、htmlがどう表示されていくのかを確認していく

v-ifを利用した場合

v-ifでbox内のheightがある場合だけ表示するように変更し、box2のheightを消して見る

<template>
  <div class="hello">
    <div v-for="box in boxs" :key="box.name" :style="[setSize(box)]" v-if="box.height">
      {{ box.name }}
    </div>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      boxs: [
        {name: 'box1', width: 100, height: 50, color: 'red'},
        {name: 'box2', width: 100, color: 'blue'},
        {name: 'box3', width: 100, height: 150, color: 'green'}
      ]
    }
  },
  methods: {
    setSize (box) {
      console.log('methods in')
      const height = box.width + box.height
      return {
        width: box.width + '%',
        height: height + 'px',
        backgroundColor: box.color
      }
    }
  }
}
</script>

結果

box2の要素が<!---->に置きかわり表示されなくなる事がわかった

ログ

boxの要素が消えた事からsetSizeには2回しか入らない事がわかった

v-showを利用した場合

先ほどv-ifで書いた場所をv-showに変更するのみ

<template>
  <div class="hello">
    <div v-for="box in boxs" :key="box.name" :style="[setSize(box)]" v-show="box.height">
      {{ box.name }}
    </div>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      boxs: [
        {name: 'box1', width: 100, height: 50, color: 'red'},
        {name: 'box2', width: 100, color: 'blue'},
        {name: 'box3', width: 100, height: 150, color: 'green'}
      ]
    }
  },
  methods: {
    setSize (box) {
      console.log('methods in')
      const height = box.width + box.height
      return {
        width: box.width + '%',
        height: height + 'px',
        backgroundColor: box.color
      }
    }
  }
}
</script>

結果

box2にはdisplay:noneのstyleが付き、html上は残っているがstyleで表示されなくなる事がわかった

ログ

box2の情報は残ったままになっているため3回ログ出力される事がわかった

まとめ

v-ifとv-showを実際に同じコードで使用してみた場合以下のようになることが分かった

html上の表示 関数を通るか?
v-if 非表示(オブジェクトremove) 通らない
v-show 非表示(display:none) 通る

画面上では表示されないのは双方変わらないが、オブジェクトがv-forで繰り返しを行う中で関数を利用している場合はv-showを使っていると意図せずに関数の中に入ってしまうことがあるので注意が必要ということがわかった

最後に

自分はサイズが必須なところでv-showを使っていてデータを入力中の中途半端な状態になった際に
関数内で計算を行おうとして画面が真っ白になってしまう失敗をしてしまった

今回は自分の議事録としてだがv-if、v-showの使い分けに悩んでいる助けになればと思います(人)