• 【Vue2.0源码学习】生命周期篇-挂载阶段(mount)


    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)
    };
    
    • 1
    • 2
    • 3
    • 4

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

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

    export function mountComponent (vm,el,hydrating) {
        vm.$el = el
        if (!vm.$options.render) {
            vm.$options.render = createEmptyVNode
        }
        callHook(vm, 'beforeMount')
    
        let updateComponent
    
        updateComponent = () => {
            vm._update(vm._render(), hydrating)
        }
        new Watcher(vm, updateComponent, noop, {
            before () {
                if (vm._isMounted) {
                    callHook(vm, 'beforeUpdate')
                }
            }
        }, true /* isRenderWatcher */)
        hydrating = false
    
        if (vm.$vnode == null) {
            vm._isMounted = true
            callHook(vm, 'mounted')
        }
        return vm
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

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

    vm.$el = el
    if (!vm.$options.render) {
        vm.$options.render = createEmptyVNode
    }
    
    • 1
    • 2
    • 3
    • 4

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

    callHook(vm, 'beforeMount')
    
    • 1

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

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

    updateComponent = () => {
        vm._update(vm._render(), hydrating)
    }
    
    • 1
    • 2
    • 3

    在该函数内部,首先执行渲染函数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                    // 第五个参数
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

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

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

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

    3. 总结

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

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

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

  • 相关阅读:
    cobol数据类型
    【NSArray数组的遍历 Objective-C语言】
    NNLM、RNNLM等语言模型 实现 下一单词预测(next-word prediction)
    SpringBoot HandlerInterceptor实战
    Windows 10系统下如何搭建轻量级目标检测NanoDet-plus环境?
    依赖注入跟::调用方法,哪种好,有什么区别?
    如何使用csproj构建C#源代码组件NuGet包?
    Java学习之多态二
    浅析“代码可视化” | 京东云技术团队
    【整合】LSTM 时间序列预测任务 Time-Series-Sine,实现正弦曲线的预测
  • 原文地址:https://blog.csdn.net/weixin_46862327/article/details/133264997