一、v-show和v-if的共同点
若不考虑v-else,v-show和v-if的作用是一样的,都能控制元素在页面是否显示。
<button v-show="isShow" />
<button v-if="isShow" />
二、v-show和v-if的区别
1、控制手段不同:v-show隐藏则是为该元素添加css(display:none),dom元素依旧还在。v-if显示隐藏是将dom元素整个添加或删除(将dom注释掉)。
2、编译过程不同:v-show知识简单的基于css切换;v-if在切换时将dom元素卸载,切换过程中会触发组件销毁和移除事件监听。
- v-show 由 false 变为 true 的时候不会触发组件的生命周期;
- v-if 由 false 变为 true 的时候,触发组件的beforeCreate、create、beforeMount、mounted钩子,由true变为false的时候触发组件的beforeDestory、destoryed方法。
三、v-show和v-if的使用场景
- v-if的开销更大(直接进行dom的创建与删除)
- 如果要频繁地切换,使用v-show更好(初始开销更大,但后续切换性能较高)
- 如果运行条件很少改变,则使用v-if更好(初始开销更小,但后续切换性能较低)
四、源码解析
v-show源码:
有transition就执行transition,没有就直接设置display属性。
// 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)
}
}
v-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 {
// 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
)
}
}
})
}
)