v-if 与 v-show 的区别
一、v-if
用于按指定条件渲染一块内容。
v-if 是惰性的:初次渲染时如果为 false
,则不会做任何事,为 true
时才被渲染。
<div v-if="show">显示内容</div>
注意
不建议在一个元素上同时使用 v-if 和 v-for,因为 v-if 比 v-for 的优先级更高,同时存在时 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名,例如:
<!--
这会抛出一个错误,因为属性 todo 此时
没有在该实例上定义
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
</li>
解决办法:在外套一层 template
使用 v-for
:
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
v-if 的源码片段:
可以看出,v-if 原理是返回一个 node
节点,render
函数通过表达式的值来决定是否生成 DOM。
vIf.ts
// https://github.com/vuejs/core/blob/main/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) => {
// #1587: We need to dynamically increment the key based on the current
// node's sibling nodes, since chained v-if/else branches are
// rendered at the same depth
const siblings = context.parent!.children
let i = siblings.indexOf(ifNode)
let key = 0
while (i-- >= 0) {
const sibling = siblings[i]
if (sibling && sibling.type === NodeTypes.IF) {
key += sibling.branches.length
}
}
// Exit callback. Complete the codegenNode when all children have been
// transformed.
return () => {
if (isRoot) {
ifNode.codegenNode = createCodegenNodeForBranch(
branch,
key,
context
) as IfConditionalExpression
} else {
// attach this branch's codegen node to the v-if root.
const parentCondition = getParentCondition(ifNode.codegenNode!)
parentCondition.alternate = createCodegenNodeForBranch(
branch,
key + ifNode.branches.length - 1,
context
)
}
}
})
}
)
二、v-show
用于按指定条件显示一个元素,用法与 v-if 基本一样:
<div v-show="show">显示内容</div>
v-show 的源码片段:
可以看出 v-show 的原理是设置 display
的方式来控制显示隐藏。
vShow.ts
// https://github.com/vuejs/core/blob/main/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)
}
}
三、二者的区别
- 相同点
作用效果相同,为 true
时都会占用页面空间,为 false
时不会。
- 不同点
v-if 是控制元素是否渲染在页面中,切换时条件区块内的事件监听器和子组件会被销毁与重建,触发组件的生命周期。
而 v-show 则始终会被渲染,只通过 display:none
来控制显示隐藏,不会触发组件的生命周期;
另外,v-if 支持在 template
上使用,而 v-show 不支持;
使用上,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,渲染后如果需要频繁切换,建议使用 v-show。