Vue.js条件渲染

条件渲染是Vue.js中用于根据条件显示或隐藏元素的重要特性。通过条件渲染,我们可以创建动态的用户界面,根据应用状态的不同显示不同的内容。

Vue提供了多种条件渲染指令,包括v-ifv-elsev-else-ifv-show。理解这些指令的区别和适用场景,对于编写高效、可维护的Vue应用至关重要。

为什么需要条件渲染?

在Web应用中,经常需要根据不同的条件显示不同的内容。例如:

用户状态

根据用户是否登录显示不同的界面,未登录用户显示登录表单,已登录用户显示用户面板。

数据加载状态

数据加载时显示加载指示器,加载完成显示内容,加载失败显示错误信息。

权限控制

根据用户权限显示或隐藏特定的功能按钮或菜单项。

表单步骤

多步骤表单中,根据当前步骤显示相应的表单字段。

Vue的条件渲染优势
  • 声明式语法:使用简洁的模板语法描述条件逻辑
  • 自动响应:条件变化时,视图自动更新
  • 多种指令:提供多种指令应对不同场景
  • 性能优化:Vue内部优化了条件渲染的性能
  • 易于维护:条件逻辑清晰,易于理解和修改

v-if 指令

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

条件表达式
true/false
渲染/不渲染
基本语法

<!-- 如果isShow为true,则渲染div -->
<div v-if="isShow">这个元素会被渲染</div>

<!-- 使用表达式 -->
<div v-if="count > 0">计数大于0</div>

<!-- 使用计算属性 -->
<div v-if="isActive">活跃状态</div>
                                
v-if 演示
✅ v-if条件为真,这个元素被渲染
✅ 数字大于10: {{ number }}
⚠️ 数字在1-10之间: {{ number }}
❌ 数字小于等于0: {{ number }}

DOM检查提示: 使用浏览器开发者工具检查元素,观察元素是否在DOM中。

v-if 的特点
  • 惰性渲染:条件为假时,元素不会被渲染到DOM中
  • 切换开销高:条件变化时,元素会被销毁和重建
  • 支持模板:可以在<template>元素上使用
  • 支持v-else:可以与v-elsev-else-if配合使用
  • 初始渲染性能好:如果初始条件为假,则不会渲染

v-else 和 v-else-if 指令

可以使用v-elsev-else-if指令来表示v-if的"else 块"和"else-if 块"。

v-if 条件
true/false
v-else-if 条件
v-else 块
v-else 和 v-else-if 语法

<!-- v-if 和 v-else -->
<div v-if="isActive">活跃状态</div>
<div v-else>非活跃状态</div>

<!-- v-if、v-else-if 和 v-else -->
<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>
                                
v-else 和 v-else-if 演示
{{ score }} 分
用户类型判断:
🛡️ 管理员权限 - 拥有所有权限
⭐ VIP用户 - 拥有高级权限
👤 普通用户 - 拥有基本权限
👋 访客 - 仅限浏览
❓ 未知用户类型
分数等级判断:
🏆 优秀 ({{ score }}分)
👍 良好 ({{ score }}分)
👌 中等 ({{ score }}分)
✅ 及格 ({{ score }}分)
❌ 不及格 ({{ score }}分)
使用要点
  • v-elsev-else-if必须紧跟在v-ifv-else-if元素之后
  • 条件链中的每个条件按顺序检查,直到找到第一个为真的条件
  • 如果所有条件都为假,则渲染v-else块(如果存在)
  • 使用v-else-if可以避免复杂的嵌套条件

v-show 指令

v-show指令根据条件展示元素,与v-if不同,v-show始终会渲染元素,只是通过CSS的display属性切换显示/隐藏。

条件表达式
true/false
display: block/none
v-show 语法

<!-- 如果isShow为true,则显示div -->
<div v-show="isShow">这个元素会被显示或隐藏</div>

<!-- 使用表达式 -->
<div v-show="count > 0">计数大于0时显示</div>
                                
v-show 演示
✅ v-show条件为真,这个元素被显示 (display: block)
❌ v-show条件为假,这个元素被隐藏 (display: none)

DOM检查提示: 使用浏览器开发者工具检查元素,无论条件如何,元素始终在DOM中,只是通过CSS控制显示/隐藏。

{{ vshowToggleCount }}
v-show 切换次数
{{ vifToggleCount }}
v-if 切换次数
{{ renderCount }}
总渲染次数

性能观察:

  • v-show: 切换时只是修改CSS属性,性能开销小
  • v-if: 切换时需要销毁和重建DOM元素,性能开销大
  • 频繁切换时,v-show性能更好

v-if vs v-show

特性 v-if v-show
渲染方式 条件性地渲染元素,条件为假时元素不会被渲染到DOM中 始终渲染元素,只是通过CSS的display属性切换显示/隐藏
初始渲染开销 较低(如果初始条件为假,则不会渲染) 较高(无论初始条件如何,都会渲染)
切换开销 较高(需要销毁和重建元素) 较低(只是切换CSS属性)
使用场景
  • 条件很少改变的场景
  • 需要惰性加载的场景
  • 条件为假时不需要保留状态的场景
  • 频繁切换显示/隐藏的场景
  • 需要保持元素状态的场景
  • 简单的显示/隐藏需求
生命周期 条件变化时会触发组件的创建/销毁生命周期钩子 条件变化时不会触发生命周期钩子,元素始终存在
与v-else配合 支持 不支持
与<template>配合 支持 不支持
性能影响 切换时性能开销大,但初始渲染可能更快 切换时性能开销小,但初始渲染可能更慢
示例

<div v-if="isLoggedIn">
  用户面板
</div>
                                            

<div v-show="isLoading">
  加载中...
</div>
                                            
何时使用 v-if vs v-show

// 适合使用 v-if 的场景:
// 1. 用户登录状态(不经常变化)
<div v-if="isLoggedIn">
  <user-panel></user-panel>
</div>
<div v-else>
  <login-form></login-form>
</div>

// 2. 权限控制(页面加载时确定)
<button v-if="user.role === 'admin'">
  删除
</button>

// 3. 需要懒加载的内容
<div v-if="loadData">
  <heavy-component></heavy-component>
</div>

// 适合使用 v-show 的场景:
// 1. 频繁切换的UI元素
<div v-show="isMenuOpen">
  <navigation-menu></navigation-menu>
</div>

// 2. 标签页切换
<div v-show="activeTab === 'profile'">
  个人资料
</div>
<div v-show="activeTab === 'settings'">
  设置
</div>

// 3. 加载状态
<div v-show="isLoading">
  <loading-spinner></loading-spinner>
</div>

// 两者结合使用
<div v-if="hasData">
  <!-- 有数据时才渲染数据容器 -->
  <div v-show="!isLoading">
    <!-- 数据加载完成时才显示 -->
    {{ data }}
  </div>
  <div v-show="isLoading">
    加载中...
  </div>
</div>
<div v-else>
  暂无数据
</div>
                                
选择指南
  • 使用 v-if:当条件不经常变化,或需要惰性加载时
  • 使用 v-show:当需要频繁切换显示/隐藏时
  • 考虑初始渲染:如果元素很少显示,使用v-if可以减少初始DOM大小
  • 考虑切换性能:如果需要频繁切换,v-show性能更好
  • 考虑状态保持:如果需要保持元素状态(如表单输入),使用v-show
  • 两者结合:复杂场景可以结合使用,发挥各自优势

在 <template> 元素上使用条件渲染

如果需要切换多个元素,可以使用<template>元素作为包裹元素,并在其上使用条件指令。<template>本身不会被渲染到DOM中。

<template> 元素演示

渲染结果:

不使用 <template>:
元素 A
元素 B
元素 C
其他元素

注:这里有一个额外的div包裹元素

使用 <template>:

注:没有额外的包裹元素,DOM结构更简洁

代码对比

<!-- 不使用 template -->
<div v-if="condition">
  <div>元素 A</div>
  <div>元素 B</div>
  <div>元素 C</div>
</div>
<div v-else>
  <div>其他元素</div>
</div>

<!-- 使用 template -->
<template v-if="condition">
  <div>元素 A</div>
  <div>元素 B</div>
  <div>元素 C</div>
</template>
<template v-else>
  <div>其他元素</div>
</template>
                                    
<template> 的特点
  • 不渲染自身<template>元素不会出现在最终的DOM中
  • 支持v-if/v-else:可以在<template>上使用条件指令
  • 不支持v-showv-show不能在<template>上使用
  • 简洁DOM:避免不必要的包裹元素,保持DOM结构简洁
  • 与v-for配合:也常用于v-for渲染多个元素

用key管理可复用的元素

Vue会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这可能会带来一些问题,特别是在表单元素中。使用key属性可以强制元素不复用。

key属性演示

切换登录方式,观察输入框状态是否保留:

不使用 key (元素会被复用):
使用 key (元素不会被复用):
代码对比

<!-- 不使用 key -->
<template v-if="loginType === 'username'">
  <label>用户名:</label>
  <input type="text" placeholder="请输入用户名">
</template>
<template v-else>
  <label>邮箱:</label>
  <input type="email" placeholder="请输入邮箱">
</template>

<!-- 使用 key -->
<template v-if="loginType === 'username'">
  <label>用户名:</label>
  <input type="text" placeholder="请输入用户名" key="username-input">
</template>
<template v-else>
  <label>邮箱:</label>
  <input type="email" placeholder="请输入邮箱" key="email-input">
</template>
                                    
key 属性的作用
  • 强制重新渲染:当key值变化时,Vue会销毁旧元素并创建新元素
  • 避免状态复用:防止表单元素在不同条件下复用导致的状态混乱
  • 提升性能:帮助Vue更准确地识别元素,提高渲染效率
  • 必要场景:表单元素切换、列表项渲染、组件切换等
  • 唯一性:key值应该是唯一的,通常使用ID或索引

条件渲染的最佳实践

应该做的
  • 优先使用计算属性:将复杂条件逻辑放在计算属性中
  • 保持条件简洁:避免在模板中写复杂的逻辑
  • 使用语义化变量名:使条件表达更清晰
  • 适当使用key:在需要避免元素复用时使用key
  • 考虑可访问性:确保隐藏的内容对屏幕阅读器友好
避免做的
  • 避免v-if和v-for一起使用:性能较差,应该使用计算属性过滤
  • 避免过度嵌套:深层嵌套的条件难以理解和维护
  • 避免重复条件:重复的条件应该提取为计算属性
  • 避免滥用v-show:大量隐藏元素仍会占用内存
  • 避免不必要的条件渲染:只在真正需要时使用条件渲染
性能优化建议
  • 合理选择v-if和v-show:根据切换频率和初始状态选择
  • 懒加载大组件:使用v-if延迟渲染开销大的组件
  • 避免不必要的重新渲染:使用key减少不必要的DOM操作
  • 使用Keep-alive:对于频繁切换的组件,使用keep-alive缓存
  • 异步组件:对于不立即需要的组件,使用异步加载

条件渲染综合演示

下面的演示展示了条件渲染的多种实际应用场景,包括用户界面切换、权限控制、表单验证等。

用户管理系统

用户状态
用户界面
未登录状态

请先登录以访问更多功能

⚡ 管理员提示: 您拥有系统最高权限,请谨慎操作
🔒 账户冻结提示: 您的账户已被冻结,部分功能不可用
条件渲染统计
v-if 使用次数
{{ vifUsageCount }}
v-show 使用次数
{{ vshowUsageCount }}
v-else 使用次数
{{ velseUsageCount }}
条件总数
{{ totalConditionCount }}
核心条件渲染代码

// 模板中的条件渲染示例
<!-- 登录状态判断 -->
<div v-if="!user.isLoggedIn">
  <!-- 未登录界面 -->
  <button @click="user.isLoggedIn = true">登录</button>
</div>

<!-- 已登录界面 -->
<template v-if="user.isLoggedIn">
  <!-- 账户状态 -->
  <div v-if="!user.isActive" class="alert alert-danger">
    账户已被冻结
  </div>

  <!-- 权限控制 -->
  <button v-if="user.role === 'admin'">
    用户管理
  </button>
  <button v-else-if="user.role === 'editor'">
    编辑文章
  </button>
  <button v-else>
    发表评论
  </button>

  <!-- 持续显示的管理员提示 -->
  <div v-show="user.role === 'admin'">
    管理员提示信息
  </div>
</template>

// 计算属性简化条件
computed: {
  canComment() {
    return this.user.role === 'user' ||
           this.user.role === 'editor' ||
           this.user.role === 'admin';
  },

  canEditArticles() {
    return this.user.role === 'editor' ||
           this.user.role === 'admin';
  },

  canManageUsers() {
    return this.user.role === 'admin';
  },

  isAccountFullyActive() {
    return this.user.isActive && this.user.emailVerified;
  }
}
                            

本章总结

  • v-if:条件性地渲染元素,条件为假时元素不会出现在DOM中
  • v-else:表示v-if的"else 块",必须紧跟在v-ifv-else-if之后
  • v-else-if:表示v-if的"else if 块",可以多次使用
  • v-show:通过CSS的display属性切换显示/隐藏,元素始终在DOM中
  • v-if vs v-showv-if适合条件不经常变化的场景,v-show适合频繁切换的场景
  • <template>元素:用于包裹多个元素,自身不会被渲染
  • key属性:强制元素不复用,避免状态混乱
  • 合理使用条件渲染可以创建动态、响应式的用户界面,提升用户体验

下一步:列表渲染

现在你已经掌握了条件渲染,接下来我们将学习Vue的列表渲染,包括v-for指令的使用,如何遍历数组和对象,以及列表渲染的性能优化。