vue源码解析——v-if和v-show各自是如何实现的元素的隐藏

 在Vue.js中,v-ifv-show是常用的指令,用于控制元素的显示和隐藏。虽然它们都可以隐藏元素,但实现的方式略有不同。在这篇博客中,我们将深入探讨v-ifv-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指令的实现主要涉及以下几个部分:

  1. 模板编译:在编译阶段,Vue会将模板编译成渲染函数,其中会解析指令并生成对应的虚拟DOM节点。
  2. 虚拟DOM:Vue使用虚拟DOM来描述页面结构,v-if指令会在虚拟DOM中表示为一个条件渲染的节点。
  3. 渲染函数:渲染函数会根据数据的变化来动态生成虚拟DOM,包括根据v-if指令的条件来决定是否渲染对应的节点。

在源码中,v-if主要体现在模板编译。

在编译阶段,Vue会将模板编译成渲染函数,其中会解析指令并生成对应的虚拟DOM节点。在 Vue 编译过程中,首先会执行 parseHTML 函数来将模板字符串解析成初始的 AST 树结构。 在生成AST语法树的过程中,解析 Vue 模板中的条件渲染指令,分别处理 v-ifv-elsev-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 指令的实现中,主要涉及以下几个生命周期钩子函数:

  1. bind:在绑定元素的 v-show 指令时调用。将元素的元素的 display 属性初始状态记录下来,以便后续使用。
  2. updatev-show 值发生改变时调用。在这个阶段,会根据新的 v-show 值来决定元素是否显示。如果新的 v-show 的值为 true,还原之前保留的元素的display属性;如果为 false,则将元素的 display 属性设置为 none,使元素隐藏。
  3. 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 中,指令的生命周期钩子函数(如 bindinsertedupdateunbind)已被废弃,取而代之的是新的 v-onv-model 钩子函数。

对于其他指令,如 v-ifv-show,它们的生命周期仍然存在,但不再是通过钩子函数来实现的。相反,它们的生命周期被融入到组件的生命周期函数中,并且通过渲染函数和响应式系统来实现。

所以,可以说 Vue3 中已经不再使用传统的指令生命周期钩子函数,但并不是所有指令的生命周期都被移除了。

为什么v-show使用display而不用opacity和visibility?

Vue 选择使用 display 属性来控制元素的显示和隐藏是因为 display 属性可以直接影响元素是否参与布局。当元素的 display 属性设置为 none 时,该元素会从文档流中完全删除,不会占用任何空间。这意味着其他元素会自动填充该元素原来的空间,从而避免了因隐藏元素而导致的布局问题。

相比之下,opacityvisibility 属性仅仅控制元素的可见性,而不会影响元素的布局。当元素的 opacity 属性设置为 0 或 visibility 属性设置为 hidden元素仍然占据原来的空间,其他元素不会自动填充该空间。这可能会导致布局问题,尤其是在动态显示和隐藏元素的场景中。

v-if和v-show如何选择

在选择 v-ifv-show 时,需要根据具体的使用场景来决定。

  • 如果需要频繁切换显示和隐藏,建议使用 v-show,因为它不会频繁地销毁和重建 DOM 元素,性能更好。
  • 如果只需要在初始渲染时做判断,并且不需要频繁切换,建议使用 v-if,因为它可以减少初始渲染时的开销。

总的来说,v-if 适用于条件渲染的场景,而 v-show 适用于频繁切换显示和隐藏的场景。

  • 27
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三月的一天

你的鼓励将是我前进的动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值