Vue 3 条件语句完全指南
本文档从零开始讲解 Vue 3 里的条件语句:如何根据数据“为真/为假”来显示或隐藏内容,包括 v-if、v-else-if、v-else、v-show 的用法、区别、常见场景和易错点,配有大量示例,适合新手系统学习。
一、为什么需要“条件”?
页面上经常要根据不同情况显示不同内容,例如:
- 已登录显示“欢迎回来”,未登录显示“请登录”
- 成绩 ≥ 90 显示“优秀”,≥ 60 显示“及格”,否则“不及格”
- 有数据时显示列表,没数据时显示“暂无数据”
- 加载中显示骨架屏,加载完显示真实内容
在 Vue 里,这类逻辑不用手写 JavaScript 去改 DOM,只要在模板里用条件指令写出“什么时候显示什么”,Vue 会帮你自动更新视图。
这些“条件指令”就是本文要讲的条件语句。
二、条件指令有哪些?
Vue 3 中与“条件”相关的指令主要有:
| 指令 | 作用简述 |
|---|---|
| v-if | 条件为真时渲染这块 DOM,为假时不渲染(从 DOM 里移除) |
| v-else-if | 紧跟在 v-if 或 v-else-if 后面,表示“否则如果……” |
| v-else | 紧跟在 v-if 或 v-else-if 后面,表示“否则” |
| v-show | 条件为真时显示元素,为假时用 CSS 隐藏(元素始终在 DOM 里) |
下面逐个详细说明,并对比 v-if 和 v-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>
isVisible为true时,页面上有“你能看见我”。- 把
isVisible改成false,这句<p>会从 DOM 里消失(不是隐藏,是移除)。
哪些值是“假”?
在 Vue 里,下面这些都会被视为假:false、、''(空字符串)、null、undefined、NaN。除此以外一般都为真。
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-if或v-else-if的元素后面,表示“如果上面条件都不满足,再判断这个条件”。 - v-else:必须紧跟在带
v-if或v-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-if、v-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>
isVisible为true:正常显示。- 为
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-if 和 v-for,v-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> |
十一、学习建议
- 先练熟 v-if / v-else-if / v-else 的组合,并记住“必须紧挨着”。
- 用
<template>包多块内容,让结构更清晰。 - 理解 v-if 和 v-show 的差别:一个是否渲染 DOM,一个是否显示;按“切换频率”和“是否希望完全不渲染”来选。
- 避免 v-if 和 v-for 写在同一元素上;复杂条件用计算属性,模板里只写一个变量。
把本文档里的示例在项目里敲一遍、改条件看效果,会掌握得更牢。更多指令用法可参考《Vue3指令.md》。祝你学习顺利。