vue源码解析——v-if和v-show各自是如何实现的元素的隐藏
在Vue.js中,
v-if
和v-show
是常用的指令,用于控制元素的显示和隐藏。虽然它们都可以隐藏元素,但实现的方式略有不同。在这篇博客中,我们将深入探讨v-if
和v-show
各自是如何实现元素的隐藏的。
v-if 指令
当我们使用
v-if
指令时,Vue.js会根据条件表达式的值来决定是否渲染元素。如果条件为真,元素会被渲染到DOM中;如果条件为假,元素会被移除。这种动态创建和销毁元素的方式,保证了页面的高效性和性能。
vue2
模板渲染
通过vue 模板编译工具看下v-if被编译后的代码Vue Template Explorer
源代码
<div v-if="exists">{{ msg }}</div>
编译后的代码
function render() {
with(this) {
return (exists) ? _c('div', [_v(_s(msg))]) : _e()
}
}
这段代码返回了一个三元表达式,表达式的条件是exists。如果
exists
为真,则渲染一个包含msg
值的<div>
元素;否则不渲染任何内容。
_c('div', [_v(_s(msg))])
:这是Vue.js编译模板时生成的渲染函数调用,用于创建一个<div>
元素,并将msg
的值作为文本内容插入到这个<div>
中。
_e()
:这也是Vue.js编译模板时生成的渲染函数调用,用于创建一个空的注释节点。
源码解析
在Vue.js的源码中,
v-if
指令的实现主要涉及以下几个部分:
- 模板编译:在编译阶段,Vue会将模板编译成渲染函数,其中会解析指令并生成对应的虚拟DOM节点。
- 虚拟DOM:Vue使用虚拟DOM来描述页面结构,
v-if
指令会在虚拟DOM中表示为一个条件渲染的节点。- 渲染函数:渲染函数会根据数据的变化来动态生成虚拟DOM,包括根据
v-if
指令的条件来决定是否渲染对应的节点。
在源码中,v-if主要体现在模板编译。
在编译阶段,Vue会将模板编译成渲染函数,其中会解析指令并生成对应的虚拟DOM节点。在 Vue 编译过程中,首先会执行
parseHTML
函数来将模板字符串解析成初始的 AST 树结构。 在生成AST语法树的过程中,解析 Vue 模板中的条件渲染指令,分别处理v-if
、v-else
、v-else-if
指令,并将相应的信息存储在元素的属性中,以便后续在渲染时根据条件来动态显示或隐藏元素。
然后在 AST 转换阶段,
preTransformNode
函数会被调用用于对 AST 节点进行预处理。
vue3
模板渲染
vue3模板渲染地址:Vue Template Explorer
源代码
<div v-if="exists">{{ msg }}</div>
编译后的代码
import { toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock, createCommentVNode as _createCommentVNode } from "vue"
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_ctx.exists)
? (_openBlock(), _createElementBlock("div", { key: 0 }, _toDisplayString(_ctx.msg), 1 /* TEXT */))
: _createCommentVNode("v-if", true)
}
是不是跟vue2差不多啊,也是一个三元表达式。条件成立的话创建一个div,条件不成立的话返回一个注释节点。
源码解析
v-show指令
当使用
v-show
指令时,Vue 会根据条件动态地切换元素的display
CSS 属性,以实现显示和隐藏的效果。当条件为真时,Vue 会将display
属性还原为之前的值,而不是直接设置为block
。当条件为假时,元素的display
属性被设置为none
,元素隐藏。
vue2源码
Vue 2.x 源码中,
v-show
指令的实现是在 src\platforms\web\runtime\directives\show.ts 文件中完成的。
在 v-show
指令的实现中,主要涉及以下几个生命周期钩子函数:
- bind:在绑定元素的
v-show
指令时调用。将元素的元素的display
属性初始状态记录下来,以便后续使用。 - update:
v-show
值发生改变时调用。在这个阶段,会根据新的v-show
值来决定元素是否显示。如果新的v-show
的值为true
,还原之前保留的元素的display属性;如果为false
,则将元素的display
属性设置为none
,使元素隐藏。 - unbind:在组件更新完成后调用。
v-show
指令会将元素的display
属性重置为初始状态。
vue3源码
Vue 3.x 源码中,
v-show
指令的实现是在 packages\runtime-dom\src\directives\vShow.ts
Vue 3 中的
v-show
指令并没有单独的生命周期钩子,而是在组件的更新周期中通过响应式数据的变化来控制元素的显示与隐藏。 这跟vue2是有区别的。
v-show
指令的生命周期可以看作是整个组件的生命周期,包括创建、更新和销毁等阶段。
-
创建阶段beforeMount/mounted:在组件创建阶段,
v-show
指令会根据初始绑定的值来确定元素的显示状态。 -
更新阶段updated:在组件更新阶段,如果绑定的响应式数据发生变化,
v-show
指令会根据新的值来更新元素的显示状态。 -
销毁阶段beforeUnmount:在组件销毁阶段,
v-show
指令会随着组件的销毁而被清除,元素的显示状态也会相应地被销毁。
为什么vue3中v-show不使用指令的生命周期?
在 Vue3 中,指令的生命周期钩子函数(如
bind
、inserted
、update
和unbind
)已被废弃,取而代之的是新的v-on
和v-model
钩子函数。对于其他指令,如
v-if
和v-show
,它们的生命周期仍然存在,但不再是通过钩子函数来实现的。相反,它们的生命周期被融入到组件的生命周期函数中,并且通过渲染函数和响应式系统来实现。所以,可以说 Vue3 中已经不再使用传统的指令生命周期钩子函数,但并不是所有指令的生命周期都被移除了。
为什么v-show使用display而不用opacity和visibility?
Vue 选择使用
display
属性来控制元素的显示和隐藏是因为display
属性可以直接影响元素是否参与布局。当元素的display
属性设置为none
时,该元素会从文档流中完全删除,不会占用任何空间。这意味着其他元素会自动填充该元素原来的空间,从而避免了因隐藏元素而导致的布局问题。
相比之下,opacity
和 visibility
属性仅仅控制元素的可见性,而不会影响元素的布局。当元素的 opacity
属性设置为 0 或 visibility
属性设置为 hidden
时,元素仍然占据原来的空间,其他元素不会自动填充该空间。这可能会导致布局问题,尤其是在动态显示和隐藏元素的场景中。
v-if和v-show如何选择
在选择
v-if
和v-show
时,需要根据具体的使用场景来决定。
- 如果需要频繁切换显示和隐藏,建议使用
v-show
,因为它不会频繁地销毁和重建 DOM 元素,性能更好。 - 如果只需要在初始渲染时做判断,并且不需要频繁切换,建议使用
v-if
,因为它可以减少初始渲染时的开销。
总的来说,
v-if
适用于条件渲染的场景,而v-show
适用于频繁切换显示和隐藏的场景。
更多推荐
所有评论(0)