Vue 中的 v-show 和 v-if 怎么理解?
一、v-show 与 v-if 的共同点
我们都知道在 vue 中 v-show 与 v-if 的作用效果是相同的(不含 v-else),都能控制元素在页面是否显示。
在用法上也是相同的:
<Modal v-show="isShow" />
<Modal v-if="isShow" />
二、v-show 与 v-if 的区别
| 维度 | v-show | v-if |
|---|---|---|
| 控制手段 | 设置 display: none,DOM 元素依旧还在 | 将 DOM 元素整个添加或删除 |
| 编译过程 | 只是简单的基于 CSS 切换 | 切换有一个局部编译/卸载的过程,会销毁和重建内部的事件监听和子组件 |
| 编译条件 | 元素总是会被渲染 | 真正的条件渲染,确保条件块内的事件监听和子组件被适当地销毁和重建;条件为假时什么都不做 |
| 性能消耗 | 更高的初始渲染消耗 | 更高的切换消耗 |
三、v-show 与 v-if 原理分析
v-show 原理
不管初始条件是什么,元素总是会被渲染。
// https://github.com/vuejs/vue-next/blob/3cd30c5245da0733f9eb6f29d220f39c46518162/packages/runtime-dom/src/directives/vShow.ts
export const vShow: ObjectDirective<VShowElement> = {
beforeMount(el, { value }, { transition }) {
el._vod = el.style.display === 'none' ? '' : el.style.display
if (transition && value) {
transition.beforeEnter(el)
} else {
setDisplay(el, value)
}
},
mounted(el, { value }, { transition }) {
if (transition && value) {
transition.enter(el)
}
},
updated(el, { value, oldValue }, { transition }) {
// ...
},
beforeUnmount(el, { value }) {
setDisplay(el, value)
}
}
有 transition 就执行 transition,没有就直接设置 display 属性。
v-if 原理
v-if 在实现上比 v-show 要复杂得多,因为还有 else / else-if 等条件需要处理。返回一个 node 节点,render 函数通过表达式的值来决定是否生成 DOM:
// https://github.com/vuejs/vue-next/blob/cdc9f336fd/packages/compiler-core/src/transforms/vIf.ts
export const transformIf = createStructuralDirectiveTransform(
/^(if|else|else-if)$/,
(node, dir, context) => {
return processIf(node, dir, context, (ifNode, branch, isRoot) => {
// ...
return () => {
if (isRoot) {
ifNode.codegenNode = createCodegenNodeForBranch(
branch,
key,
context
) as IfConditionalExpression
} else {
const parentCondition = getParentCondition(ifNode.codegenNode!)
parentCondition.alternate = createCodegenNodeForBranch(
branch,
key + ifNode.branches.length - 1,
context
)
}
}
})
}
)
四、v-show 与 v-if 的使用场景
- v-if 与 v-show 都能控制 DOM 元素在页面的显示。
- v-if 相比 v-show 开销更大(直接操作 DOM 节点增加与删除)。
- 如果需要非常频繁地切换,则使用 v-show 较好。
- 如果在运行时条件很少改变,则使用 v-if 较好。
来源整理自:vue3js.cn 面试官系列



