Vue源码系列讲解——生命周期篇【八】(挂载阶段)

1. 前言

模板编译阶段完成之后,接下来就进入了挂载阶段,从官方文档给出的生命周期流程图中可以看到,挂载阶段所做的主要工作是创建Vue实例并用其替换el选项对应的DOM元素,同时还要开启对模板中数据(状态)的监控,当数据(状态)发生变化时通知其依赖进行视图更新。

2. 挂载阶段分析

在上篇文章介绍模板编译阶段中我们说过,在完整版本的$mount方法中将模板编译完成之后,会回过头去调只包含运行时版本的$mount方法进入挂载阶段,所以要想分析挂载阶段我们必须从只包含运行时版本的$mount方法入手。

只包含运行时版本的$mount代码如下:

Vue.prototype.$mount = function (el,hydrating) {el = el && inBrowser ? query(el) : undefined;return mountComponent(this, el, hydrating)
};

可以看到,在该函数内部首先获取到el选项对应的DOM元素,然后调用mountComponent函数并将el选项对应的DOM元素传入,进入挂载阶段。那么,下面我们来看下mountComponent函数内部都干了些什么。

mountComponent函数的定义位于源码的src/core/instance/lifecycle.js中,如下:

export function mountComponent (vm,el,hydrating) {vm.$el = elif (!vm.$options.render) {vm.$options.render = createEmptyVNode}callHook(vm, 'beforeMount')let updateComponentupdateComponent = () => {vm._update(vm._render(), hydrating)}new Watcher(vm, updateComponent, noop, {before () {if (vm._isMounted) {callHook(vm, 'beforeUpdate')}}}, true /* isRenderWatcher */)hydrating = falseif (vm.$vnode == null) {vm._isMounted = truecallHook(vm, 'mounted')}return vm
}

可以看到,在该函数中,首先会判断实例上是否存在渲染函数,如果不存在,则设置一个默认的渲染函数createEmptyVNode,该渲染函数会创建一个注释类型的VNode节点。如下:

vm.$el = el
if (!vm.$options.render) {vm.$options.render = createEmptyVNode
}

然后调用callHook函数来触发beforeMount生命周期钩子函数,如下:

callHook(vm, 'beforeMount')

该钩子函数触发后标志着正式开始执行挂载操作。

接下来定义了一个updateComponent函数,如下:

updateComponent = () => {vm._update(vm._render(), hydrating)
}

在该函数内部,首先执行渲染函数vm._render()得到一份最新的VNode节点树,然后执行vm._update()方法对最新的VNode节点树与上一次渲染的旧VNode节点树进行对比并更新DOM节点(即patch操作),完成一次渲染。

也就是说,如果调用了updateComponent函数,就会将最新的模板内容渲染到视图页面中,这样就完成了挂载操作的一半工作,即图中的上半部分:

为什么说是完成了一半操作呢?这是因为在挂载阶段不但要将模板渲染到视图中,同时还要开启对模板中数据(状态)的监控,当数据(状态)发生变化时通知其依赖进行视图更新。即图中的下半部分:

继续往下看,接下来创建了一个Watcher实例,并将定义好的updateComponent函数传入。要想开启对模板中数据(状态)的监控,这一段代码是关键,如下:

new Watcher(vm,                    // 第一个参数updateComponent,       // 第二个参数noop,                  // 第三个参数{                      // 第四个参数before () {if (vm._isMounted) {callHook(vm, 'beforeUpdate')}}},true                    // 第五个参数
)

可以看到,在创建Watcher实例的时候,传入的第二个参数是updateComponent函数。回顾一下我们在数据侦测篇文章中介绍Watcher类的时候,Watcher类构造函数的第二个参数支持两种类型:函数和数据路径(如a.b.c)。如果是数据路径,会根据路径去读取这个数据;如果是函数,会执行这个函数。一旦读取了数据或者执行了函数,就会触发数据或者函数内数据的getter方法,而在getter方法中会将watcher实例添加到该数据的依赖列表中,当该数据发生变化时就会通知依赖列表中所有的依赖,依赖接收到通知后就会调用第四个参数回调函数去更新视图。

换句话说,上面代码中把updateComponent函数作为第二个参数传给Watcher类从而创建了watcher实例,那么updateComponent函数中读取的所有数据都将被watcher所监控,这些数据中只要有任何一个发生了变化,那么watcher都将会得到通知,从而会去调用第四个参数回调函数去更新视图,如此反复,直到实例被销毁。

这样就完成了挂载阶段的另一半工作。

如此之后,挂载阶段才算是全部完成了,接下来调用挂载完成的生命周期钩子函数mounted

3. 总结

本篇文章介绍了生命周期中的第三个阶段——挂载阶段。

在该阶段中所做的主要工作是创建Vue实例并用其替换el选项对应的DOM元素,同时还要开启对模板中数据(状态)的监控,当数据(状态)发生变化时通知其依赖进行视图更新。

我们将挂载阶段所做的工作分成两部分进行了分析,第一部分是将模板渲染到视图上,第二部分是开启对模板中数据(状态)的监控。两部分工作都完成以后挂载阶段才算真正的完成了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2813671.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【Pytorch深度学习开发实践学习】B站刘二大人课程笔记整理lecture09 Softmax多分类

代码: import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader import torch.nn as nn import torch.nn.functional as Fbatch_size 64 transform transforms.Compose([transforms.ToTensor(), transforms.Normali…

【HarmonyOS】鸿蒙开发之Stage模型-基本概念——第4.1章

Stage模型-基本概念 名词解释 AbilityStage:应用组件的“舞台“ UIAbility:包含UI界面的应用组件,是系统调度的基本单元 WindowStage:组件内窗口的“舞台“ Window:用来绘制UI页面的窗口 HAP:Harmony Ability Package(鸿蒙能力类型的包) HSP:Harmony Sh…

【洛谷学习自留】p5707 上学迟到

解题思路: 1.先用给出的时间和速度(如果无法整除,则时间加一),计算出时间(分),然后将时间加上10分钟。 2.创建一个计时器,设置一个日期,保证时分秒部分&#…

Linux安装jdk、tomcat、MySQL离线安装与启动

一、JDK和Tomcat的安装 1.JDK安装 直接上传到Linux服务器的,上传jdk、tomcat安装包 解压JDK安装包 //解压jdk tar -zxvf jdk-8u151-linux-x64.tar.gz 置环境变量(JAVA_HOME和PATH) vim /etc/profile 在文件末尾添加以下内容: //java environment expo…

使用R语言进行线性回归模型异常点分析

一、数据集描述 某厂生产的一种电器年销售量Y与竞争对手的价格X1及本厂的价格X2有关,数据如下: 10个城市某种电器的年销售量和竞争对手的价格(单位:元)X1X2YX1X2Y1201001021401101001909012013015077155210461751509…

Redis 管道详解

Redis 管道 关键词:Pipeline Pipeline 简介 Redis 是一种基于 C/S 模型以及请求/响应协议的 TCP 服务。通常情况下,一个 Redis 命令的请求、响应遵循以下步骤: 客户端向服务端发送一个查询请求,并监听 Socket 返回&#xff08…

GEE入门篇|遥感专业术语(实践操作4):光谱分辨率(Spectral Resolution)

目录 光谱分辨率(Spectral Resolution) 1.MODIS 2.EO-1 光谱分辨率(Spectral Resolution) 光谱分辨率是指传感器进行测量的光谱带的数量和宽度。 您可以将光谱带的宽度视为每个波段的波长间隔,在多个波段测量辐射亮…

width:100%和width:auto有啥区别

项目中使用了with属性,突然好奇auto 和 100% 的区别,特地搜索实践总结了一下观点 一、 width属性介绍二、 代码带入三、 分析比较四、 总结 一、 width属性介绍 width 属性用于设置元素的宽度。width 默认设置内容区域的宽度,但如果 box-siz…

【Unity每日一记】角色控制器Character Contorller

👨‍💻个人主页:元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏:Uni…

动态规划(简单习题)

数字三角形 Number Triangles 首先我看到这个题目就在思考应该用怎样一个数据结构来存放这些数据,是二叉树,还是并查集那样的连接。 第二个问题这个使用动态规划应该怎样构建状态转移方程,使用dfs来遍历然后使用一个数组来存放最大价值吗&…

wps 365 批量修改.xlsx、.xls,单元格内容的格式为yyyy-mm-dd

xlsx、xls文件导入校验单元格内容格式有误,批量修改步骤如下 1.选中要修改内容的单元格列 2.选择数据-分列-分列,弹出“文本分列向导”弹窗 3.选择“下一步”——“下一步”到步骤3,在“列数据类型”中选中日期-YMD格式,点击“完成…

【C++进阶】深入了解继承机制

目录 前言 1. 继承的概念 2. 继承的定义 3. 继承中基类与派生类的赋值转换 4. 继承中的作用域 5. 派生类的默认成员函数 6. 继承与友元、静态成员 7. 多继承与菱形继承 7.1 如何解决 前言 继承是面向对象编程中的一个重要概念,也是面向对象编程语言中普遍存在的特…

主数据管理是数字化转型成功的基石——江淮汽车案例分享

汽车行业数字化转型的背景 在新冠疫情导火索的影响下,经济全球化政治基础逐渐动摇。作为全球最大的汽车市场,我国的汽车市场逐渐由增量转为存量市场。 在数字化改革大背景下,随着工业4.0时代的到来,江淮汽车集团力争实现十四五数…

BFS中的双向广搜和A-star

双向广搜 190. 字串变换 - AcWing题库 import java.util.*;public class Main{static int N 6, n 0;//规则数不超过6个,n表示规则数量static String[] a new String[N];//字串a,用于规则变换static String[] b new String[N];//字串b,用…

2.2 RK3399项目开发实录-使用USB线缆升级固件(物联技术666)

2.1. 前言 本文介绍了如何将主机上的固件,通过USB数据线烧录到 AIO-3399J 开发板的存储器中。升级时,需要根据主机操作系统和固件类型来选择合适的升级方式。 2.2. 准备工具 AIO-3399J 开发板 固件 主机 良好的双公头USB数据线数据线 2.3. 准备固件 …

leetcode 2.合并两个有序链表

1..题目:合并两个有序链表; 2.用例: 3.解题思路: (1)函数头:参数是两个链表;返回值为 链表指针 ListNode*; (2)函数体: 1.首先比较…

python学习笔记-内置异常

概述 Python 中的异常(Exception)是指在程序执行过程中遇到的错误或异常情况。当程序出现异常时,解释器会停止当前代码的执行,并试图找到匹配的异常处理器来处理异常。如果没有找到合适的异常处理器,程序就会终止并打…

PDF文件转换为图片

现在确实有很多线上的工具可以把pdf文件转为图片,比如smallpdf等等,都很好用。但我们有时会碰到一些敏感数据,或者要批量去转,那么需要自己写脚本来实现,以下脚本可以提供这个功能~ def pdf2img(pdf_dir, result_path…

搭建Facebook直播网络对IP有要求吗?

在当今数字化时代,Facebook直播已经成为了一种极具吸引力的社交形式,为个人和企业提供了与观众直接互动的机会,成为推广产品、分享经验、建立品牌形象的重要途径。然而,对于许多人来说,搭建一个稳定、高质量的Facebook…

【Godot4.2】菜单栏生成函数库menuDB

概述 关于Godot的手动菜单栏制作,我已经在之前的文章中有所描述。 但是对于一些场景,手动制作菜单仍然是一个比较低效的做法。所以我将MenuBar以及基于HBoxContainerMenuButton创建菜单栏写成了一个静态函数库。 利用此函数库我们可以用函数形式构造P…