【Vue.js】v-ifで条件分岐させる方法

【Vue.js】v-ifで条件分岐させる方法 Vue.js

画面の一部を、データの状態によって出したり隠したりしたい場面は多くあります。ログインの有無、通信の成功や失敗、権限の違いなどです。Vueで最もよく使うのがv-ifです。この記事では、Vue 3(<script setup>)を前提に、基本の使い方から、v-showとの違い、つまずきやすい点までを動くコードで整理します。

スポンサーリンク

基本の使い方

v-ifに渡した式が真のときだけ、その要素が描画されます。偽のときは、要素そのものがDOMに存在しません。ボタンで切り替える例です。

Vue:v-ifの基本
<script setup>
import { ref } from 'vue'

const isVisible = ref(true)
</script>

<template>
  <p v-if="isVisible">このテキストは表示されます</p>
  <button @click="isVisible = !isVisible">表示/非表示を切り替える</button>
</template>

複数の条件で分岐する

v-else-ifとv-elseを組み合わせると、if〜else ifの文のように書けます。

Vue:v-else-ifとv-else
<script setup>
import { ref } from 'vue'

const status = ref('unknown')
</script>

<template>
  <p v-if="status === 'success'">成功しました!</p>
  <p v-else-if="status === 'error'">エラーが発生しました。</p>
  <p v-else>ステータスが不明です。</p>

  <button @click="status = 'success'">成功</button>
  <button @click="status = 'error'">エラー</button>
  <button @click="status = 'unknown'">不明</button>
</template>

注意点として、v-elseとv-else-ifは、直前の要素がv-ifまたはv-else-ifでなければ認識されません。間に別の要素を挟むと動きません。

Vue:v-elseは直前に置く
<!-- NG:間に別の要素があると v-else が認識されない -->
<p v-if="ok">OK</p>
<hr>
<p v-else>NG</p>

<!-- OK:v-if の直後に v-else を置く -->
<p v-if="ok">OK</p>
<p v-else>NG</p>

templateで複数の要素をまとめて出し分ける

複数の要素を同じ条件で出し分けたいときは、<template>にv-ifを付けます。<template>自体はDOMに出力されないので、余分な要素が増えません。v-elseとv-else-ifも使えます。

Vue:templateにv-ifを付ける
<!-- 複数の要素を、余分なDOMを増やさずにまとめて出し分ける -->
<template v-if="isLoggedIn">
  <h2>マイページ</h2>
  <p>ようこそ、{{ user.name }}さん</p>
  <button @click="logout">ログアウト</button>
</template>
<template v-else>
  <p>ログインしてください。</p>
</template>

ネストした条件分岐

v-ifの中に、さらにv-ifを置くこともできます。ログイン済みのときだけユーザー名を出し、その中で管理者にだけ追加のメッセージを出す例です。

Vue:ネストしたv-if
<script setup>
import { ref } from 'vue'

const user = ref(null)

function login() {
  user.value = { name: 'ユーザー名', isAdmin: true }
}
function logout() {
  user.value = null
}
</script>

<template>
  <div v-if="user">
    <p>ようこそ、{{ user.name }}さん!</p>
    <p v-if="user.isAdmin">管理者としてログインしています。</p>
  </div>
  <p v-else>ログインしてください。</p>

  <button @click="login">ログイン</button>
  <button @click="logout">ログアウト</button>
</template>

v-ifとv-showの違い

表示を切り替える方法には、v-showもあります。違いは、DOMに対する扱いです。

Vue:v-ifとv-show
<!-- v-if:条件が偽のとき、要素そのものを描画しない -->
<h1 v-if="ok">Hello!</h1>

<!-- v-show:常に描画し、CSSの display だけを切り替える -->
<h1 v-show="ok">Hello!</h1>

<!-- v-show は <template> と v-else には使えない -->
  • v-if:偽のとき、要素を描画しません。真になるたびに要素を作り直すため、切り替えのコストは高めです。その代わり、初回の描画で不要な要素を作らないので、初期表示のコストは低くなります。
  • v-show:要素は常に描画され、CSSのdisplayだけを切り替えます。切り替えのコストは低く、初期の描画コストは高めです。<template>とv-elseには使えません。

目安として、頻繁に切り替えるものはv-show、条件があまり変わらないものはv-ifを使います。

v-ifとv-forを同じ要素に書かない

v-ifとv-forを同じ要素に書くと、優先順位があいまいになります。Vue 3ではv-ifが先に評価されますが、Vue 2ではv-forが先でした。公式も、同じ要素に書くことは避けるよう勧めています。絞り込みはcomputedで行ってから、v-forに渡すと分かりやすくなります。

Vue:computedで絞り込んでからv-forに渡す
<script setup>
import { ref, computed } from 'vue'

const todos = ref([
  { id: 1, title: '買い物', done: false },
  { id: 2, title: '掃除', done: true }
])

// 未完了のものだけに絞り込んでから v-for に渡す
const activeTodos = computed(() => todos.value.filter(t => !t.done))
</script>

<template>
  <!-- NG:同じ要素に v-if と v-for を書く(Vue 2 と 3 で優先順位が逆) -->
  <!-- <li v-for="todo in todos" v-if="!todo.done"> -->

  <!-- OK:computed で絞り込む -->
  <ul>
    <li v-for="todo in activeTodos" :key="todo.id">{{ todo.title }}</li>
  </ul>
</template>

リスト表示の詳細はv-forで配列やオブジェクトをループして表示する方法をご覧ください。

関連記事

よくある質問(FAQ)

Qv-ifとv-showはどう使い分けますか?
A頻繁に切り替える要素は、displayだけを変えるv-showが向いています。条件があまり変わらない要素は、偽のときに描画しないv-ifが向いています。
Qv-elseが動かないのはなぜですか?
Av-elseやv-else-ifの直前の要素が、v-ifまたはv-else-ifになっていない可能性があります。間に別の要素を挟まないでください。
Q複数の要素をまとめて表示・非表示にするには?
A<template v-if="…">で囲みます。<template>はDOMに出力されないので、余分な要素が増えません。v-showは<template>に使えません。
Qv-ifとv-forを同じ要素に書いてもよいですか?
A避けてください。Vue 3ではv-ifが優先されますが、Vue 2ではv-forが優先で、挙動が逆でした。computedで絞り込んだ配列をv-forに渡す書き方がおすすめです。

まとめ

v-ifは、条件が偽のときに要素を描画しない条件分岐です。v-else-ifとv-elseは直前に置き、複数の要素は<template>でまとめます。頻繁に切り替えるならv-show、v-forとの併用はcomputedで絞り込む、という使い分けを押さえておくと迷いません。