Vue3条件语句

Vue 3 条件语句完全指南

本文档从零开始讲解 Vue 3 里的条件语句:如何根据数据“为真/为假”来显示或隐藏内容,包括 v-ifv-else-ifv-elsev-show 的用法、区别、常见场景和易错点,配有大量示例,适合新手系统学习。


一、为什么需要“条件”?

页面上经常要根据不同情况显示不同内容,例如:

  • 已登录显示“欢迎回来”,未登录显示“请登录”
  • 成绩 ≥ 90 显示“优秀”,≥ 60 显示“及格”,否则“不及格”
  • 有数据时显示列表,没数据时显示“暂无数据”
  • 加载中显示骨架屏,加载完显示真实内容

在 Vue 里,这类逻辑不用手写 JavaScript 去改 DOM,只要在模板里用条件指令写出“什么时候显示什么”,Vue 会帮你自动更新视图。
这些“条件指令”就是本文要讲的条件语句


二、条件指令有哪些?

Vue 3 中与“条件”相关的指令主要有:

指令 作用简述
v-if 条件为时渲染这块 DOM,为时不渲染(从 DOM 里移除)
v-else-if 紧跟在 v-ifv-else-if 后面,表示“否则如果……”
v-else 紧跟在 v-ifv-else-if 后面,表示“否则”
v-show 条件为时显示元素,为时用 CSS 隐藏(元素始终在 DOM 里)

下面逐个详细说明,并对比 v-ifv-show 该怎么选。


三、v-if:条件为真才渲染

3.1 基本用法

语法: v-if="表达式"
表达式的值为真(truthy)时,这个元素会被渲染到页面上;为假(falsy)时,整块元素不会出现在 DOM 里

<template>
  <div>
    <p v-if="isVisible">你能看见我</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const isVisible = ref(true)
</script>
  • isVisibletrue 时,页面上有“你能看见我”。
  • isVisible 改成 false,这句 <p> 会从 DOM 里消失(不是隐藏,是移除)。

哪些值是“假”?
在 Vue 里,下面这些都会被视为假:false''(空字符串)、nullundefinedNaN。除此以外一般都为真。

3.2 表达式可以是变量,也可以是运算

v-if 里写的是单个 JavaScript 表达式,和 {{ }} 里能写的类型一样。

<template>
  <div>
    <p v-if="count > 0">有内容</p>
    <p v-if="name && name.length > 0">你好,{{ name }}</p>
    <p v-if="list.length">列表有 {{ list.length }} 项</p>
    <p v-if="type === 'admin'">管理员可见</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const count = ref(5)
const name = ref('小明')
const list = ref([1, 2, 3])
const type = ref('admin')
</script>

四、v-else-if 与 v-else:多分支“否则如果 / 否则”

当有多种情况要分别显示不同内容时,可以用 v-if + v-else-if + v-else,和编程里的 if / else if / else 一一对应。

4.1 基本结构

  • v-else-if:必须紧跟在带 v-ifv-else-if 的元素后面,表示“如果上面条件都不满足,再判断这个条件”。
  • v-else:必须紧跟在带 v-ifv-else-if 的元素后面不能写表达式,表示“上面条件都不满足时就走这里”。
<template>
  <div>
    <p v-if="score >= 90">优秀</p>
    <p v-else-if="score >= 60">及格</p>
    <p v-else>不及格</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const score = ref(85)
</script>
  • score 为 85:只显示“及格”(第一个为假,第二个为真)。
  • 改为 95:只显示“优秀”。
  • 改为 50:只显示“不及格”。

重要: v-else-ifv-else 必须和前面的 v-if / v-else-if 紧紧挨着,中间不能插入别的没有条件指令的标签,否则会报错或行为异常。

4.2 多分支示例:根据状态显示不同文案

<template>
  <div>
    <p v-if="status === 'loading'">加载中...</p>
    <p v-else-if="status === 'success'">加载成功</p>
    <p v-else-if="status === 'error'">加载失败,请重试</p>
    <p v-else>未知状态</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const status = ref('loading') // 可改为 'success'、'error' 等看效果
</script>

4.3 可以只有 v-if 和 v-else(两个分支)

<template>
  <div>
    <p v-if="isLoggedIn">欢迎回来</p>
    <p v-else>请先登录</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const isLoggedIn = ref(false)
</script>

五、用 包住多块内容做条件

有时你希望一整块(多个标签)根据同一个条件一起显示或一起不显示,而不是给每个标签都写一遍 v-if
可以用 <template> 包住这一整块,在 <template> 上写 v-if
<template> 是 Vue 的虚拟容器,不会在 DOM 里多出一个节点。

5.1 示例:登录 / 未登录两套内容

<template>
  <div>
    <template v-if="isLoggedIn">
      <h2>欢迎回来,{{ username }}</h2>
      <p>这是你的个人中心</p>
      <button @click="logout">退出登录</button>
    </template>
    <template v-else>
      <h2>请先登录</h2>
      <input v-model="username" placeholder="用户名" />
      <button @click="login">登录</button>
    </template>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const isLoggedIn = ref(false)
const username = ref('')
function login() {
  isLoggedIn.value = true
}
function logout() {
  isLoggedIn.value = false
}
</script>

这样“登录后的整块”和“未登录的整块”会随 isLoggedIn 切换,结构清晰。

5.2 template 也可配合 v-else-if、v-else

<template>
  <div>
    <template v-if="type === 'A'">
      <p>A 类型内容</p>
    </template>
    <template v-else-if="type === 'B'">
      <p>B 类型内容</p>
    </template>
    <template v-else>
      <p>其他类型</p>
    </template>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const type = ref('B')
</script>

六、v-show:用 CSS 显示/隐藏,不移除 DOM

语法: v-show="表达式"
当表达式为时,元素正常显示;为时,Vue 会给元素加上 style="display: none;",元素仍然在 DOM 里,只是看不见。

<template>
  <div>
    <p v-show="isVisible">看得见我</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const isVisible = ref(true)
</script>
  • isVisibletrue:正常显示。
  • false<p> 还在 DOM 里,但被 display: none 隐藏。

v-show 没有 v-else-if / v-else。每个元素各自写自己的 v-show 条件即可。


七、v-if 和 v-show 怎么选?(重要)

对比项 v-if v-show
为假时 元素不渲染,从 DOM 里移除 元素仍在 DOM,只是 display: none
切换成本 每次从假变真要重新创建 DOM,从真变假要销毁 只改 CSS,不增删 DOM
初始为假 不会渲染,少一次创建 会先渲染再隐藏
适用场景 不常切换、或希望“为假时完全不渲染” 频繁切换显示/隐藏

简单记忆:

  • 很少切换(如根据登录状态显示不同区域)→ 用 v-if,逻辑清晰,为假时完全不占 DOM。
  • 频繁切换(如 Tab 切换、折叠展开)→ 用 v-show,避免反复创建/销毁 DOM,性能更好。
<template>
  <div>
    <!-- 登录状态很少在短时间内反复切换,用 v-if 合适 -->
    <div v-if="isLoggedIn">欢迎回来</div>
    <div v-else>请登录</div>

    <!-- 下面这个 Tab 可能用户会频繁点击切换,用 v-show 更合适 -->
    <div v-show="tab === 'list'">列表内容</div>
    <div v-show="tab === 'chart'">图表内容</div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const isLoggedIn = ref(true)
const tab = ref('list')
</script>

八、常见场景示例

8.1 根据数据是否为空显示“暂无数据”

<template>
  <div>
    <ul v-if="list.length > 0">
      <li v-for="item in list" :key="item.id">{{ item.name }}</li>
    </ul>
    <p v-else>暂无数据</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const list = ref([]) // 空数组时显示“暂无数据”
// const list = ref([{ id: 1, name: '第一项' }]) // 有数据时显示列表
</script>

也可写成:v-if="list.length"(长度为 0 时为假)。

8.2 加载中 / 成功 / 失败三种状态

<template>
  <div>
    <div v-if="status === 'loading'">加载中,请稍候...</div>
    <div v-else-if="status === 'error'">
      <p>加载失败:{{ errorMessage }}</p>
      <button @click="retry">重试</button>
    </div>
    <div v-else>
      <p>加载成功,数据条数:{{ list.length }}</p>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const status = ref('loading') // 'loading' | 'error' | 'success'
const errorMessage = ref('')
const list = ref([])
function retry() {
  status.value = 'loading'
  // 这里可以重新请求数据
}
</script>

8.3 根据权限或角色显示不同内容

<template>
  <div>
    <button v-if="role === 'admin'">删除</button>
    <button v-else-if="role === 'editor'">编辑</button>
    <span v-else>仅可查看</span>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const role = ref('admin') // 'admin' | 'editor' | 'viewer'
</script>

8.4 多个条件都满足才显示(逻辑与)

<template>
  <div>
    <p v-if="isLoggedIn && isVip">尊贵的 VIP,欢迎回来</p>
    <p v-else-if="isLoggedIn">欢迎回来</p>
    <p v-else>请登录</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const isLoggedIn = ref(true)
const isVip = ref(true)
</script>

8.5 复杂条件抽成计算属性,模板更清晰

条件很长时,建议放到 计算属性 里,模板里只写一个变量名,可读性更好。

<template>
  <div>
    <p v-if="canEdit">你可以编辑</p>
    <p v-else>你只能查看</p>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
const role = ref('editor')
const status = ref('active')
const canEdit = computed(() => {
  return role.value === 'admin' || (role.value === 'editor' && status.value === 'active')
})
</script>

九、易错点与注意点

9.1 v-else-if、v-else 必须紧挨着 v-if

下面这样是错误的,中间多了一个没条件的 <p>

<!-- 错误示例 -->
<p v-if="a">A</p>
<p>中间多了一行</p>
<p v-else>B</p>

正确做法:要么去掉中间的 <p>,要么给中间那行也加上条件(如 v-else-if),或把 v-else 写在紧挨着的前一个条件块上。

9.2 不要在同一元素上同时写 v-if 和 v-for

Vue 3 里,同一元素上若同时有 v-ifv-forv-if 会先执行,且可能拿不到预期的循环变量,容易出错。
推荐:用 <template> 包一层,在 <template> 上写 v-for,在子元素上写 v-if;或用计算属性先过滤再循环。

<!-- 不推荐:同一元素 v-if + v-for -->
<li v-for="item in list" v-if="item.visible" :key="item.id">...</li>

<!-- 推荐:template 包一层 -->
<template v-for="item in list" :key="item.id">
  <li v-if="item.visible">...</li>
</template>

9.3 想“切换时重新创建”可加 :key

有时你希望:条件从假变真时,这块内容要“重新建一遍”(例如表单清空、动画重新播)。
可以给这块根元素加 :key,并在条件变化时改变 key 的值,Vue 就会先销毁再重新创建。

<template>
  <div>
    <template v-if="isEdit">
      <form :key="'edit-' + userId">
        <input v-model="form.name" />
      </form>
    </template>
    <template v-else>
      <p>查看模式</p>
    </template>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const isEdit = ref(false)
const userId = ref(1)
const form = ref({ name: '' })
</script>

userId 变化时,因为 key 变了,表单会被重新创建,适合“切换用户时重置表单”的场景。

9.4 注意“假值”带来的意外

v-if="value" 时,若 value''null,条件为假,块不会渲染。
若你本意是“有传这个 prop 就显示”,要区分“未传”和“传了 0”等情况,可以用更明确的条件,例如:

<p v-if="count !== undefined && count !== null">数量:{{ count }}</p>
<!-- 或 -->
<p v-if="typeof count === 'number'">数量:{{ count }}</p>

十、条件语句速查表

需求 写法
为真才渲染 v-if="表达式"
否则如果 v-else-if="表达式"(紧跟在上一个 v-if/v-else-if 后)
否则 v-else(紧跟在上一个 v-if/v-else-if 后,无表达式)
为假时隐藏(不删 DOM) v-show="表达式"
多块一起条件 <template v-if="..."> 包住多块
多分支 + 多块 <template v-if> / <template v-else-if> / <template v-else>

十一、学习建议

  1. 先练熟 v-if / v-else-if / v-else 的组合,并记住“必须紧挨着”。
  2. <template> 包多块内容,让结构更清晰。
  3. 理解 v-if 和 v-show 的差别:一个是否渲染 DOM,一个是否显示;按“切换频率”和“是否希望完全不渲染”来选。
  4. 避免 v-if 和 v-for 写在同一元素上;复杂条件用计算属性,模板里只写一个变量。

把本文档里的示例在项目里敲一遍、改条件看效果,会掌握得更牢。更多指令用法可参考《Vue3指令.md》。祝你学习顺利。

发表评论