Vue条件渲染详解:v-if、v-show用法与实战指南

0 阅读9分钟

在Vue开发中,页面交互往往需要根据不同的状态展示不同的内容——比如用户登录后显示个人中心,未登录时显示登录按钮;表单验证失败时显示错误提示,成功时显示提交成功信息。这种“按需显示”的需求,Vue提供了一套简洁高效的条件渲染方案,核心就是v-if、v-else、v-else-if和v-show这几个指令。今天就从基础用法到进阶技巧,全方位拆解Vue条件渲染,帮你精准掌握不同场景下的最优使用方式,写出更灵活、可维护的前端代码。

核心指令:v-if 系列——“按需渲染”的核心

v-if 是Vue中最基础、最常用的条件渲染指令,它的核心作用是:根据绑定表达式的真假,决定是否渲染当前元素及它的子元素。当表达式为真值(Truthy)时,元素会被渲染到DOM中;当表达式为假值(Falsy)时,元素会被从DOM中移除,而非简单隐藏。

1. v-if 基础用法:单个条件判断

v-if 可以直接绑定一个响应式状态,实现简单的“显示/隐藏”切换。需要注意的是,v-if 是一个指令,必须依附于某个具体的DOM元素,不能单独使用。

实战示例:根据用户登录状态显示不同内容

<script setup>
import { ref } from 'vue';

// 模拟用户登录状态:true为已登录,false为未登录
const isLogin = ref(false);

// 模拟登录操作
function login() {
  isLogin.value = true;
}

// 模拟退出登录操作
function logout() {
  isLogin.value = false;
}
</script>

<template>
  <div class="user-section">
    <!-- 已登录时显示个人中心入口 -->
    <button v-if="isLogin" @click="logout">退出登录</button>
    <span v-if="isLogin" class="user-info">欢迎回来,用户123</span>
    
    <!-- 未登录时显示登录按钮 -->
    <button v-if="!isLogin" @click="login">立即登录</button>
  </div>
</template>

<style>
.user-section {
  margin: 20px 0;
  padding: 15px;
  border: 1px solid #eee;
}
.user-info {
  margin: 0 10px;
  color: #42b983;
}
button {
  padding: 6px 12px;
  cursor: pointer;
  border: none;
  border-radius: 4px;
  background: #42b983;
  color: white;
}
button:hover {
  opacity: 0.9;
}
</style>

image.png

image.png

2. v-else:补充v-if的“否则”场景

当v-if的条件不成立时,我们可以用v-else指令添加一个“否则”的渲染区块。需要特别注意的是,v-else 必须紧跟在v-if 或 v-else-if 元素之后,不能单独存在,也不能插入其他元素,否则Vue会无法识别。

实战示例:优化登录状态显示(用v-else简化代码)

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

function toggleLogin() {
  isLogin.value = !isLogin.value;
}
</script>

<template>
  <div class="user-section">
    <button @click="toggleLogin">{{ isLogin ? '退出登录' : '立即登录' }}</button>
    <!-- v-if 和 v-else 紧跟,实现互斥显示 -->
    <div v-if="isLogin" class="user-info">
      欢迎回来,用户123<br/>
      <a href="#">进入个人中心</a>
    </div>
    <div v-else class="login-tip">
      请登录后查看更多内容 😊
    </div>
  </div>
</template>

<style>
/* 样式沿用上面的基础样式,新增提示样式 */
.login-tip {
  margin-top: 10px;
  color: #666;
  font-size: 14px;
}
</style>

3. v-else-if:多条件分支判断

当需要判断多个条件分支时,v-else-if 可以实现“if-else if-else”的逻辑,它可以连续使用多次,最终用v-else收尾(可选)。同样,v-else-if 必须紧跟在v-if 或前一个v-else-if 元素之后。

实战示例:根据用户等级显示不同权限提示

<script setup>
import { ref } from 'vue';

// 模拟用户等级:0-普通用户,1-会员,2-管理员
const userLevel = ref(1);

// 切换用户等级
function changeLevel(level) {
  userLevel.value = level;
}
</script>

<template>
  <div class="level-section">
    <button @click="changeLevel(0)">普通用户</button>
    <button @click="changeLevel(1)">会员用户</button>
    <button @click="changeLevel(2)">管理员</button>
    
    <div class="level-tip" v-if="userLevel === 0">
      普通用户:可查看基础内容,解锁更多功能请升级会员
    </div>
    <div class="level-tip" v-else-if="userLevel === 1">
      会员用户:可查看专属内容,享受优先客服服务
    </div>
    <div class="level-tip" v-else-if="userLevel === 2">
      管理员:拥有全部操作权限,可管理所有用户数据
    </div>
    <div class="level-tip" v-else>
      未知用户等级,请联系管理员
    </div>
  </div>
</template>

<style>
.level-section {
  margin: 20px 0;
  padding: 15px;
  border: 1px solid #eee;
}
.level-tip {
  margin-top: 15px;
  padding: 10px;
  border-radius: 4px;
}
.level-tip:nth-child(2) { background: #f5fafe; color: #4299e1; }
.level-tip:nth-child(3) { background: #fdf2f8; color: #9f7aea; }
.level-tip:nth-child(4) { background: #eaf6fa; color: #38b2ac; }
.level-tip:nth-child(5) { background: #faf0f5; color: #e53e3e; }
</style>

4. template 上的v-if:批量切换多个元素

v-if 必须依附于单个DOM元素,但如果我们需要同时切换多个元素的显示/隐藏,又不想额外添加一个包裹容器(比如div),就可以在template标签上使用v-if。template只是一个不可见的包装器,最终渲染的结果不会包含这个标签,完美解决“多元素切换”的需求。

实战示例:批量切换表单提示信息

<script setup>
import { ref } from 'vue';

// 模拟表单提交状态:true为提交成功,false为未提交
const submitSuccess = ref(false);

function submitForm() {
  // 模拟表单提交逻辑
  setTimeout(() => {
    submitSuccess.value = true;
  }, 1000);
}
</script>

<template>
  <form class="form" @submit.prevent="submitForm">
    <input type="text" placeholder="请输入内容" required />
    <button type="submit">提交</button>
    
    <!-- 用template包裹多个元素,批量切换显示/隐藏 -->
    <template v-if="submitSuccess">
      <div class="success-icon"></div>
      <p class="success-tip">表单提交成功!感谢您的反馈</p>
      <button type="button" @click="submitSuccess = false">重新提交</button>
    </template>
  </form>
</template>

<style>
.form {
  margin: 20px 0;
  padding: 15px;
  border: 1px solid #eee;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
input {
  padding: 8px;
}
.success-icon {
  font-size: 24px;
  color: #48bb78;
}
.success-tip {
  color: #48bb78;
  margin: 5px 0;
}
</style>

image.png

image.png

另一种选择:v-show 指令——“简单隐藏”的高效方案

除了v-if,Vue还提供了v-show指令用于条件显示元素,它的用法和v-if非常相似,都是通过绑定表达式的真假来控制元素的显示状态,但二者的底层实现和使用场景有很大区别。

v-show 的核心特点:无论条件是否成立,元素都会被渲染到DOM中,它只是通过切换元素的CSS display属性来控制显示/隐藏(display: none 或 display: 初始值),元素本身始终存在于DOM中。

v-show 基础用法

v-show 直接绑定响应式状态,语法和v-if一致,适合简单的显示/隐藏切换场景。

<script setup>
import { ref } from 'vue';

// 模拟开关状态
const isShow = ref(true);

function toggleShow() {
  isShow.value = !isShow.value;
}
</script>

<template>
  <div class="show-section">
    <button @click="toggleShow">{{ isShow ? '隐藏' : '显示' }}内容</button>
    <div v-show="isShow" class="show-content">
      这是v-show控制的内容,隐藏时只是display: none,不会从DOM中移除
    </div>
  </div>
</template>

<style>
.show-section {
  margin: 20px 0;
  padding: 15px;
  border: 1px solid #eee;
}
.show-content {
  margin-top: 10px;
  padding: 10px;
  background: #f5f5f5;
}
</style>

注意:v-show 不支持在template标签上使用,也不能和v-else搭配使用,只能单独作用于单个DOM元素。

关键对比:v-if vs v-show 怎么选?

很多初学者会混淆v-if和v-show的用法,其实二者的核心区别在于“是否从DOM中移除元素”,这也决定了它们的适用场景。下面通过表格清晰对比,帮你快速判断:

对比维度v-ifv-show
DOM存在性条件为假时,元素从DOM中移除无论条件真假,元素始终在DOM中
实现方式动态创建/销毁DOM元素切换CSS display属性
初始渲染开销惰性渲染:条件为假时不渲染,初始开销小无论条件如何,都会渲染,初始开销大
切换开销创建/销毁DOM,切换开销大仅切换CSS,切换开销小
适用场景条件很少切换(如登录/未登录状态)条件需要频繁切换(如弹窗、tab切换)
支持搭配支持v-else、v-else-if,支持template不支持v-else,不支持template

实战建议:如果需要频繁切换显示状态(比如导航菜单、弹窗),优先用v-show;如果条件切换频率低(比如用户身份判断、页面权限控制),优先用v-if,这样能减少DOM节点数量,提升页面性能。

进阶注意:v-if 与 v-for 的使用禁忌

在实际开发中,我们可能会遇到“需要过滤列表后渲染”的场景,这时容易习惯性地将v-if和v-for写在同一个元素上,但这种用法是Vue不推荐的,因为二者的优先级不明确,会导致渲染异常和性能问题。

Vue中,当v-if和v-for同时存在于一个元素上时,v-if会先执行,也就是说,Vue会先判断每个列表项是否满足v-if的条件,再进行循环渲染,这会导致v-for的循环次数增加,影响性能。

错误示例(不推荐)

<!-- 错误:v-if和v-for写在同一个元素上 -->
<ul>
  <li v-for="item in list" v-if="item.status === 1" :key="item.id">
    {{ item.name }}
  </li>
</ul>

正确做法(推荐)

方案1:先通过计算属性过滤列表,再用v-for渲染,避免v-if和v-for同元素

<script setup>
import { ref, computed } from 'vue';

const list = ref([
  { id: 1, name: 'Vue基础', status: 1 },
  { id: 2, name: 'React基础', status: 0 },
  { id: 3, name: 'Vue条件渲染', status: 1 },
  { id: 4, name: 'JavaScript进阶', status: 0 }
]);

// 计算属性过滤状态为1的列表项
const activeList = computed(() => {
  return list.value.filter(item => item.status === 1);
});
</script>

<template>
  <ul>
    <!-- 只渲染过滤后的列表,无需v-if -->
    <li v-for="item in activeList" :key="item.id">
      {{ item.name }}
    </li>
  </ul>
</template>

方案2:用template包裹v-for,将v-if写在template上(适用于整体过滤列表)

<template>
  <!-- 先判断列表是否有数据,再循环渲染 -->
  <template v-if="list.length > 0">
    <ul>
      <li v-for="item in list" :key="item.id">
        {{ item.name }}
      </li>
    </ul>
  </template>
  <div v-else>
    暂无数据
  </div>
</template>

常见误区与避坑指南

  1. v-else、v-else-if 位置错误:必须紧跟在v-if或v-else-if元素之后,不能插入其他元素,否则会被Vue识别为无效指令;
  2. v-show 用于复杂组件:v-show 会始终渲染元素,即使条件为假,复杂组件的初始渲染会增加页面加载时间,建议改用v-if;
  3. v-if 用于频繁切换场景:频繁切换v-if会导致DOM频繁创建/销毁,产生性能开销,建议改用v-show;
  4. v-if 和 v-for 同元素使用:优先级混乱,导致渲染异常和性能问题,优先用计算属性过滤列表;
  5. 在template上使用v-show:v-show不支持template标签,会导致指令失效,需改为作用于具体DOM元素。

总结:条件渲染的最佳实践

Vue的条件渲染指令(v-if、v-else、v-else-if、v-show)为我们提供了灵活的页面交互方案,核心是根据场景选择合适的指令,兼顾性能和可读性。结合实战场景,提炼以下最佳实践:

  1. 简单显示/隐藏、频繁切换:用v-show,减少DOM切换开销;
  2. 条件切换少、需要销毁DOM:用v-if,减少初始渲染和DOM节点数量;
  3. 多条件分支:用v-if + v-else-if + v-else,确保指令顺序正确;
  4. 批量切换多个元素:用template包裹v-if,避免额外添加容器;
  5. 过滤列表渲染:用计算属性过滤列表后,再用v-for渲染,避免v-if和v-for同元素;
  6. 避免无效指令:v-show不搭配v-else、不用于template,v-else不单独使用。

掌握条件渲染的核心用法和场景差异,能让你在Vue开发中更灵活地控制页面展示,写出更高效、可维护的代码。条件渲染是Vue页面交互的基础,后续结合列表渲染、组件封装等知识点,还能实现更复杂的页面逻辑,解锁更多前端开发技巧。