文章目录
- 前言
- 一、v-if 条件渲染
- 1.1 定义
- 1.2 分支语法
- 1.3 生命周期影响
- 二、v-show 显示隐藏
- 2.1 定义
- 2.2 不支持的场景
- 三、核心区别
- 3.1 机制对比
- 3.2 性能差异
- 四、应用场景区分
- 4.1 适合 v-if 的场景
- 4.2 适合 v-show 的场景
- 五、v-if 与 v-for 优先级
- 5.1 Vue 2 vs Vue 3
- 5.2 Vue 3 推荐写法
- 六、SSR 场景
- 6.1 v-show 在 SSR 中的问题
- 七、面试聚焦
- 7.1 生命周期差异
- 7.2 初始渲染开销
- 八、易混淆点
- 九、思考与练习
- 总结
前言
v-if和v-show是 Vue 中控制元素显示与隐藏的两种方式,理解它们的区别对性能优化至关重要。本篇会讲清楚:
- v-if 的动态创建/销毁机制
- v-show 的 CSS 切换机制
- 两者的性能差异与选型
- v-if 与 v-for 的优先级问题
一、v-if 条件渲染
1.1 定义
v-if是条件渲染指令,通过动态创建和销毁 DOM 节点来控制元素的显示与隐藏。
<template> <!-- 条件为 false 时,元素完全不存在于 DOM 中 --> <div v-if="show">显示内容</div> </template>1.2 分支语法
<template> <!-- 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>其他类型</div> <!-- 在 <template> 上使用 --> <template v-if="show"> <h1>标题</h1> <p>内容</p> </template> </template>1.3 生命周期影响
<script setup> import { ref, onMounted, onUnmounted } from 'vue' const show = ref(false) // 组件 A 的生命周期 onMounted(() => console.log('A 挂载')) onUnmounted(() => console.log('A 卸载')) </script> <template> <!-- show 从 false → true:触发 onMounted --> <!-- show 从 true → false:触发 onUnmounted --> <ComponentA v-if="show" /> </template>二、v-show 显示隐藏
2.1 定义
v-show通过切换 CSSdisplay属性来控制元素的可见性,DOM 节点始终存在。
<template> <!-- 条件为 false 时,元素仍在 DOM 中,只是 display: none --> <div v-show="show">显示内容</div> </template>2.2 不支持的场景
<template> <!-- ❌ 错误:v-show 不能用在 <template> 上 --> <template v-show="show"> <div>内容</div> </template> <!-- ❌ 错误:v-show 不支持 v-else --> <div v-show="show">显示</div> <!-- <div v-else>隐藏</div> 语法错误 --> </template>三、核心区别
3.1 机制对比
| 对比项 | v-if | v-show |
|---|---|---|
| 实现方式 | 动态创建/销毁 DOM | 切换 CSS display |
| DOM 节点 | 条件为 false 时不存在 | 始终存在 |
| 初始渲染 | 条件为 false 时无开销 | 始终渲染 |
| 切换开销 | 高(创建/销毁) | 低(切换样式) |
| 生命周期 | 触发创建/销毁钩子 | 不触发任何钩子 |
| template | 支持 | 不支持 |
| v-else | 支持 | 不支持 |
3.2 性能差异
// 场景 1:条件很少变化// ✅ 推荐 v-if:初始渲染开销低(条件为 false 时不渲染)// ❌ v-show:始终渲染,浪费// 场景 2:频繁切换// ✅ 推荐 v-show:切换开销低(只切换样式)// ❌ v-if:每次切换都要创建/销毁 DOM四、应用场景区分
4.1 适合 v-if 的场景
<template> <!-- 1. 权限控制:条件很少变化 --> <AdminPanel v-if="isAdmin" /> <UserPanel v-else /> <!-- 2. 角色判断:运行时条件固定 --> <div v-if="role === 'editor'">编辑器</div> <div v-else-if="role === 'viewer'">查看器</div> <!-- 3. 条件渲染多个元素 --> <template v-if="isLoggedIn"> <UserProfile /> <UserSettings /> </template> <!-- 4. 懒加载组件:首次需要时才创建 --> <HeavyComponent v-if="showHeavy" /> </template>4.2 适合 v-show 的场景
<template> <!-- 1. Tab 切换:频繁切换 --> <div v-show="activeTab === 'tab1'">Tab 1 内容</div> <div v-show="activeTab === 'tab2'">Tab 2 内容</div> <div v-show="activeTab === 'tab3'">Tab 3 内容</div> <!-- 2. 折叠面板:频繁展开/收起 --> <div class="panel"> <div class="header" @click="expanded = !expanded">标题</div> <div v-show="expanded" class="content">内容</div> </div> <!-- 3. Tooltip / Popover:频繁显隐 --> <div v-show="tooltipVisible" class="tooltip">提示内容</div> <!-- 4. 加载状态:频繁切换 --> <div v-show="loading" class="spinner">加载中...</div> </template>五、v-if 与 v-for 优先级
5.1 Vue 2 vs Vue 3
<template> <!-- Vue 2:v-for 优先级更高 --> <!-- 先遍历,再判断条件 --> <li v-for="item in list" v-if="item.active"> {{ item.name }} </li> <!-- Vue 3:v-if 优先级更高 --> <!-- 先判断条件,但 item 未定义! --> <!-- ❌ 错误写法 --> </template>5.2 Vue 3 推荐写法
<script setup> import { ref, computed } from 'vue' const list = ref([ { id: 1, name: 'A', active: true }, { id: 2, name: 'B', active: false }, { id: 3, name: 'C', active: true } ]) // ✅ 推荐:用 computed 过滤 const activeList = computed(() => list.value.filter(item => item.active)) </script> <template> <!-- ✅ 正确:直接遍历过滤后的列表 --> <li v-for="item in activeList" :key="item.id"> {{ item.name }} </li> <!-- ✅ 或者用 <template> 包裹 --> <template v-for="item in list" :key="item.id"> <li v-if="item.active"> {{ item.name }} </li> </template> </template>六、SSR 场景
6.1 v-show 在 SSR 中的问题
<template> <!-- v-show 在服务端渲染时无效 --> <!-- 因为服务端无法操作 DOM 的 display 属性 --> <!-- 服务端返回的 HTML 始终包含该元素 --> <div v-show="show">内容</div> <!-- ✅ SSR 推荐使用 v-if --> <!-- 条件为 false 时,服务端不会渲染该元素 --> <div v-if="show">内容</div> </template>七、面试聚焦
7.1 生命周期差异
// v-if:切换时触发组件的创建/销毁生命周期// false → true:触发 onMounted// true → false:触发 onUnmounted// v-show:不触发任何生命周期钩子// 始终存在于 DOM 中7.2 初始渲染开销
// v-if:条件为 false 时,初始渲染无开销(不创建 DOM)// v-show:无论条件如何,始终渲染 DOM(有初始渲染开销)// 场景:条件默认为 false,首次需要时才显示// v-if:首次无开销,切换时有开销// v-show:首次有开销,切换时无开销八、易混淆点
- v-show 不可用在
<template>上:<template>不会渲染为真实 DOM,无法设置display属性。 - v-show 不支持 v-else:v-show 是简单的样式切换,不支持分支语法。
- SSR 场景 v-show 无效:服务端无法操作 DOM 的
display属性,应使用 v-if。 - Vue 3 的优先级变化:v-if 优先级高于 v-for,Vue 2 中相反,这是常见迁移坑点。
- v-if 有"惰性":条件为 false 时,内部组件不会被创建;切换到 true 时才会创建。
九、思考与练习
1.v-if 和 v-show 的核心区别是什么?
解析:
- v-if:动态创建/销毁 DOM,切换开销高,初始渲染开销低
- v-show:切换 CSS display,切换开销低,初始渲染开销高
2.什么场景用 v-if,什么场景用 v-show?
解析:
- v-if:条件很少变化(权限控制、角色判断)
- v-show:频繁切换(Tab、折叠面板、Tooltip)
3.v-show 为什么不能用在<template>上?
解析:<template>不会渲染为真实 DOM 节点,而 v-show 需要通过操作 DOM 的display属性来切换显示,所以无法在<template>上使用。
4.Vue 3 中 v-if 和 v-for 一起用会怎样?
解析:Vue 3 中 v-if 优先级高于 v-for,会导致 v-if 中无法访问 v-for 的变量。推荐用 computed 先过滤列表,或用<template>包裹。
5.v-show 在 SSR 中为什么无效?
解析:SSR 是在服务端生成 HTML,服务端无法操作 DOM 的display属性。v-show 始终渲染元素到 HTML 中,无法在服务端实现隐藏效果,应使用 v-if。
总结
- v-if:动态创建/销毁 DOM,适合条件很少变化的场景
- v-show:切换 CSS display,适合频繁切换的场景
- v-if 有分支语法:v-if / v-else-if / v-else
- v-show 不支持
<template>和 v-else - v-if 触发生命周期:创建/销毁钩子
- v-show 不触发生命周期
- Vue 3 优先级:v-if > v-for
- SSR 场景:v-show 无效,用 v-if