1、共同点
皆可动态控制DOM元素的显示与隐藏
2、区别
v-if
- 动态的向DOM树内添加或者删除DOM元素
- 真正的条件渲染,它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;在初始渲染条件为假时,什么也不做。
- 由于存在销毁和重建,具有更高的切换消耗
v-show
- 通过设置DOM元素的display样式属性控制显示和隐藏
- 不管初始条件是什么,元素总是会被渲染,只是简单地基于 CSS 进行切换。
- 由于总是会被渲染,所以初始时有更高的渲染消耗
3、原理剖析
v-if
const VueTemplateCompiler = require('vue-template-compiler')
const template = '<div v-if="true"><span>hello world</span></div>'
// 模版编译成render方法
const compile = VueTemplateCompiler.compile(template)
console.log(compile.render)
// 结果
with (this) { return (true) ? _c('div', [_c('span', [_v("hello world")])]) : _e() }
满足条件时会创建DOM元素,不满足时会通过_e
创建空节点,在vue/src/core/instance/render-helpers/index.js
可以看到_e
方法的定义target._e = createEmptyVNode
v-show
const VueTemplateCompiler = require('vue-template-compiler')
const template = '<div v-show="true"><span>hello world</span></div>'
// 模版编译成render方法
const compile = VueTemplateCompiler.compile(template)
console.log(compile.render)
// 结果:true
with (this) { return _c('div', { directives: [{ name: "show", rawName: "v-show", value: (true), expression: "true" }] }, [_c('span', [_v("hello world")])]) }
// 结果:false
with (this) { return _c('div', { directives: [{ name: "show", rawName: "v-show", value: (false), expression: "false" }] }, [_c('span', [_v("hello world")])]) }
编译出v-show
的指令其他并没有特殊处理,然后我们去看看v-show
到底做了什么,找到vue/src/platforms/web/runtime/directives/show.js
,会发现以下核心代码
bind (el: any, { value }: VNodeDirective, vnode: VNodeWithData) {
vnode = locateNode(vnode)
const transition = vnode.data && vnode.data.transition
const originalDisplay = el.__vOriginalDisplay =
el.style.display === 'none' ? '' : el.style.display
if (value && transition) {
vnode.data.show = true
enter(vnode, () => {
el.style.display = originalDisplay
})
} else {
el.style.display = value ? originalDisplay : 'none'
}
},
从代码里可以看出v-show
是通过改变CSS style.display
来操作元素的显示与隐藏
4、应用场景
v-if
适合运行条件很少改变的情况,例如涉及到根据用户权限(不常变化)动态显示菜单,
v-show
适合频繁切换的情况,例如tab切换时子模块变化情景,且会保留用户之前的操作状态