v-show
和 v-if
是 Vue.js 中两个非常重要的指令,都用于条件性地显示或隐藏元素,但它们的实现方式和适用场景有本质区别。
简单来说,最核心的区别是:
v-if
是 “真正的”条件渲染,它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。v-show
只是简单地切换 CSS 属性display: none
。
下面从多个维度进行详细的对比。
对比表格
特性 | v-if | v-show |
---|---|---|
实现机制 | 动态添加/移除 DOM 元素 | 切换 CSS 的 display: none 属性 |
初始渲染成本 | 高(如果初始为 false,则什么都不做,直到第一次为 true 时才渲染) | 高(无论初始条件如何,元素都会被编译并渲染,只是通过 CSS 隐藏) |
切换开销 | 高(销毁和重建组件/元素、触发生命周期钩子) | 低(只是切换 CSS 属性,非常高效) |
生命周期 | 会触发 组件的 created , mounted , destroyed 等生命周期钩子 | 不会触发 任何生命周期钩子(因为组件始终存在,只是被隐藏) |
编译/惰性 | 惰性的:如果初始条件为假,则不会编译或渲染,直到条件第一次变为真。 | 非惰性的:无论初始条件如何,元素都会被编译并保留在 DOM 中。 |
用法 | 任何条件渲染 | 适用于需要非常频繁切换的场景 |
不适合场景 | 需要非常频繁切换的场景(因为切换开销大) | 不适合初始条件为假且永远不需要显示的情况(因为仍然会渲染) |
与 v-else 配合 | 支持 | 不支持 |
与 <template> 配合 | 支持(可以包裹多个元素) | 不支持 |
详细说明与示例
1. 实现机制与 DOM 结构
v-if
:
当条件为 false
时,对应的元素或组件完全不会出现在 DOM 中。当条件变为 true
时,Vue 会开始编译并渲染它们,并将其插入到 DOM 中。
<div v-if="isVisible">使用 v-if 控制</div>
- 当
isVisible
为false
时,检查元素结构,你会发现这个<div>
根本不存在。 - 当
isVisible
为true
时,这个<div>
会被创建并插入到 DOM 中。
v-show
:
无论条件为何,元素始终会被编译并保留在 DOM 中。它只是通过内联的 CSS 样式 display: none
来切换显示和隐藏。
<div v-show="isVisible">使用 v-show 控制</div>
- 当
isVisible
为false
时,检查元素结构,你会发现这个<div>
仍然在 DOM 中,但它有内联样式style="display: none;"
。 - 当
isVisible
为true
时,内联样式会被移除,变为style=""
,元素正常显示。
2. 生命周期
由于 v-if
会真正地销毁和重建元素及其子组件,因此它会触发完整的生命周期钩子。
<ChildComponent v-if="isVisible" />
- 当
isVisible
从true
变为false
时,ChildComponent
会被销毁,触发beforeDestroy
和destroyed
钩子。 - 当
isVisible
从false
变为true
时,ChildComponent
会重新创建,触发beforeCreate
,created
,beforeMount
,mounted
等钩子。
而对于 v-show
,由于组件始终存在于 DOM 中,只是被隐藏,所以无论怎么切换,它的生命周期钩子都只会在初始渲染时触发一次。
3. 性能考量
选择使用哪个指令,主要取决于你需要的切换频率。
-
需要频繁切换时(如:切换标签页、显示/隐藏过滤器、toggle 开关),使用
v-show
。- 原因:它的切换成本极低,仅仅是修改 CSS,避免了频繁销毁和重建组件带来的性能开销。
-
运行时条件很少改变,或者初始条件很可能为 false 时,使用
v-if
。- 原因:它具有惰性,如果初始不为真,可以避免不必要的编译和渲染成本,从而加快初始页面加载速度。
总结与如何选择
记住这个简单的原则:
v-if
就像是 “彻底销毁”。不用的时候直接拆掉,用的时候再重新盖。适合变化不频繁、条件判断复杂(常与v-else-if
连用)或者对初始加载性能有要求的场景。v-show
就像是 “拉上窗帘”。东西还在屋里,只是你看不见。适合需要非常频繁切换显示状态的场景。
简单决策流程图:
- 需要频繁显示/隐藏吗? (是 -> 用
v-show
) - 这个元素在大多数情况下根本不需要显示吗? (是 -> 用
v-if
,节省初始渲染开销) - 条件逻辑复杂,需要配合
v-else
或v-else-if
吗? (是 -> 用v-if
) - 不确定?默认先考虑使用
v-if
,因为它的惰性特性在很多时候对性能更友好,除非你遇到了明显的性能问题(比如切换卡顿)再考虑换成v-show
。