条件渲染 v-if

v-if 指令用于根据表达式的真假来条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值时被渲染。

基本用法

<div id="app">
  <p v-if="seen">现在你看到我了</p>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    seen: true
  }
})
</script>

seenfalse 时,<p> 元素会被完全移除,而不是隐藏。

v-else 和 v-else-if

v-if 可以和 v-elsev-else-if 配合使用:

<div id="app">
  <div v-if="type === 'A'">
    A 类型
  </div>
  <div v-else-if="type === 'B'">
    B 类型
  </div>
  <div v-else-if="type === 'C'">
    C 类型
  </div>
  <div v-else>
    不是 A/B/C
  </div>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    type: 'A'
  }
})
</script>

注意v-elsev-else-if 必须紧跟在 v-ifv-else-if 后面,否则不会被识别。

<!-- ❌ 错误:中间有其他元素 -->
<div v-if="ok">Yes</div>
<p>其他内容</p>
<div v-else>No</div>

<!-- ✅ 正确:紧密相连 -->
<div v-if="ok">Yes</div>
<div v-else>No</div>

在 template 上使用

如果想切换多个元素,但又不想添加额外的 DOM 元素,可以使用 <template>

<template v-if="ok">
  <h1>标题</h1>
  <p>段落 1</p>
  <p>段落 2</p>
</template>

<template> 不会被渲染到最终 DOM 中,只是作为逻辑分组使用。

用 key 管理可复用元素

Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头渲染。这可能导致一些意外行为:

<div id="app">
  <template v-if="loginType === 'username'">
    <label>用户名</label>
    <input placeholder="输入用户名">
  </template>
  <template v-else>
    <label>邮箱</label>
    <input placeholder="输入邮箱">
  </template>
  <button @click="toggle">切换</button>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    loginType: 'username'
  },
  methods: {
    toggle: function() {
      this.loginType = this.loginType === 'username' ? 'email' : 'username'
    }
  }
})
</script>

切换登录方式时,输入框中已输入的内容不会清除,因为 Vue 复用了 <input> 元素。

如果需要两个输入框完全独立,添加 key 属性:

<template v-if="loginType === 'username'">
  <label>用户名</label>
  <input placeholder="输入用户名" key="username-input">
</template>
<template v-else>
  <label>邮箱</label>
  <input placeholder="输入邮箱" key="email-input">
</template>

现在每次切换,输入框都会重新渲染。

v-if vs v-show

v-show 也可以控制元素显示,但原理不同:

<!-- v-if:条件为假时,元素不存在于 DOM -->
<div v-if="show">v-if 内容</div>

<!-- v-show:条件为假时,元素存在但 display: none -->
<div v-show="show">v-show 内容</div>

选择建议

场景推荐
条件很少改变v-if
需要频繁切换v-show
运行时条件不可能改变v-if
初始条件为假v-if(不渲染)

性能对比

  • v-if 有更高的切换开销(需要销毁和重建)
  • v-show 有更高的初始渲染开销(无论真假都会渲染)

v-if 与 v-for 一起使用

不推荐在同一元素上使用 v-ifv-for

当它们一起使用时,v-for 优先级更高:

<!-- 这会报错,因为 todo 未定义 -->
<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo.text }}
</li>

推荐使用计算属性代替:

computed: {
  activeTodos: function() {
    return this.todos.filter(function(todo) {
      return !todo.isComplete
    })
  }
}
<li v-for="todo in activeTodos">
  {{ todo.text }}
</li>

实际应用场景

1. 权限控制

<div v-if="user.role === 'admin'">
  <button @click="deleteAll">删除所有</button>
</div>
<div v-else-if="user.role === 'editor'">
  <button @click="edit">编辑</button>
</div>
<div v-else>
  <p>您没有操作权限</p>
</div>

2. 加载状态

<div v-if="loading">
  加载中...
</div>
<div v-else-if="error">
  加载失败:{{ error }}
</div>
<div v-else>
  {{ content }}
</div>

3. 空状态处理

<div v-if="items.length === 0" class="empty-state">
  暂无数据
</div>
<div v-else>
  <div v-for="item in items" :key="item.id">
    {{ item.name }}
  </div>
</div>

4. 表单步骤

<div v-if="step === 1">
  <h2>第一步:基本信息</h2>
  <!-- 表单字段 -->
</div>
<div v-else-if="step === 2">
  <h2>第二步:详细信息</h2>
  <!-- 表单字段 -->
</div>
<div v-else-if="step === 3">
  <h2>第三步:确认</h2>
  <!-- 确认信息 -->
</div>

小结

指令说明
v-if条件为真时渲染,为假时销毁
v-else-if否则如果
v-else否则
key强制替换元素而非复用

v-if 是真正的条件渲染,适合条件很少改变的场景。