vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期

        在vue2.0中,我们经常会看到下面这张生命周期图,本次结合源码来让大家对这张生命周期图有一个简要的了解。

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第1张图片

1.beforeCreate和created:

        src/core/instance文件夹为vue方法初始化的主文件夹,入口为index.js文件。在使用vue框架的时候,我们首先要通过new Vue初始化一个vue实例:

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第2张图片

        此时是通过Vue方法中的_init来完成初始化的,我们再来详细看下_init方法:

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第3张图片

        在_init方法中通过initState来初始化实例中要用到的data和props,在初始化相应式数据的前后,分别来调用beforeCreate和created钩子,所以在beforeCreate中是不能访问实例的data和props数据的,而created可以。

2.beforeMount和mounted:

        为了能够更加全面的了解vue挂载的整个过程,来看runtime-with-compiler的代码。在使用vue-cli脚手架来安装项目的时候,经常会遇到runtime或者runtime-with-compiler的选择,这两个是什么意思呢?其实在vue中,把模板template转化成render函数的过程就叫做compile编译,一般在使用webpack打包的时候,我们会通过vue-loader插件在打包的时候就把模板转化成render函数,这样用户访问时就可以直接渲染出vnode挂载到浏览器页面,来提高挂载效率。如果我们没有通过webpack预先进行打包,而且我们在vue组件中写的是template模板的话,就需要通过runtime-with-compiler的模式,在运行时进行编译。

        在platforms文件夹中,有两个子文件夹分别是web和weex,他们的作用就是能够让vue的核心源码所产生的vnode节点树能够适配多个平台的DOM方法,从而在多个平台上运行。我们主要看web平台:

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第4张图片

        这里作者非常巧妙地将vue核心的mount方法与web平台mount时所需要的编译逻辑相结合,作者先是把vue核心mount方法缓存起来,再给实例的mount方法重新赋值,最后再调用vue的核心mount方法,进行挂载。在平台的mount函数中是通过compileToFunctions方法得到render方法,以便后续mount时生成vnode节点树。

        在web平台的mount函数中进行compile,生成render函数之后,就进入了vue通用mount函数流程,mount函数主要是运用mountComponent函数来执行挂载:

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第5张图片

        mountComponent函数在lifecycle.js文件中,首先执行beforeMount钩子函数。接着为updateComponent函数赋值:

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

        传给Watcher构造函数,此处初始化Watcher的作用就是作为管理当前正在渲染的实例的渲染,所以叫做render watcher。Watcher的构造函数如下,下面我们先来看看Watcher在实例化的时候都做了什么(提示:可以先看图后的解析):

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第6张图片

  Watcher类在src/core/observer/watcher.js中,实例化的时候会执行到this.get(),在get函数中会执行pushTarget()将当前Watcher赋值为当前的渲染watcher。(Watcher是一个监听者的实现)this.getter.call()即执行刚才所赋值的updateComponent函数。进行_render()和_update(),可以结合下面的流程图来理解实例的渲染流程,执行render函数后,生成了vnode节点树。执行了patch函数后,又生成了DOM结构,挂载到浏览器上后,再执行mounted钩子。

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第7张图片

3.beforeUpdate和updated

      下面来分析beforeUpdate和updated钩子,不过我们需要先来理解一下vue的响应式实现。在init的过程中有通过initState初始化data和props数据。本次主要讲data的初始化,在data的初始化的过程中vue只做了两件事,一个是对定义data函数返回对象的遍历,把vm._data.xxx都代理到vm.xxx上;另一个是调用observe方法观测整个data的变化,把data变成响应式。

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第8张图片

   Observe是在src/core/observer/index.js文件中,为每个响应式对象value创建一个Observer实例。

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第9张图片

        Observer函数将在传入的value对象中添加一个”__ob__”属性,将自己赋给这个属性。如果value是数组调用observeArray函数,来对每个元素单独执行observe。不然对value执行walk,在walk中执行defineReactive函数。

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第10张图片

        只有在defineReactive中,才对继续对元素真正实现响应式,即通过Object.defineProperty给对象的元素赋get和set属性。注意vue没有对数组的每个元素调用Object.defineProperty。只在数组对象上调用了Observer()。

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第11张图片

        至此讲完了vue如何实现响应式。

       上小节讲到在渲染的时候会将当前Watcher赋值为当前的渲染watcher保存到全局,再执行render函数生成vnode节点树。在生成vnode节点树时,会访问响应式对象的值,就会调用响应式对象的getter属性。所以,在初始化中实现对象的响应式之后,getter属性函数执行依赖收集。

        还是看上面的get函数,首先检查全局的渲染watcher是否存在,如果存在调用闭包中保存的dep的depend()。与watcher相对应,dep作为被监听的对象,被保存在data的数据对象当中。如下图,当dep调用depend()时:

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第12张图片

        全局渲染watcher会调用addDep()把当前的dep保存到watcher自己的依赖数组中。代码如下,然后再调用dep的addSub方法,dep依赖将当前的渲染watcher保存到自己的subs数组中,留待在调用set属性函数时调用notify函数(如上图),来通知subs数组里保存的watcher:

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第13张图片

        整体的逻辑关系总结如下:getter()产生了响应式数据中dep的depend调用,之后这个dep与当前的渲染watcher分别调用addSub和addDep方法,分别记录了彼此。在setter()时,dep调用notify,来逐个调用监听它的watcher的update方法。

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第14张图片

    了解了整个响应式流程,我们来关注下vue在哪里调用beforeUpdate和updated钩子。上文提到响应式数据会让watcher调用update,函数如下,在update函数中会调用queueWatcher:

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第15张图片

   而queueWatcher会调用flushSchedulerQueue方法,代码如下:

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第16张图片

      在flushSchedulerQueue方法中会调用watcher的before方法,即初始化watcher时传入的beforeUpdate钩子,最后调用callUpdatedHooks来调用updated钩子。

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第17张图片

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第18张图片

4.beforeDestory和destroyed

      最后来分析beforeDestory和destroyed钩子,其实这两个钩子是比较简单的vue通过一个原型方法调用了这两个钩子:

vue 3.0和2.0区别_通过Vue2.0源码理解vue生命周期_第19张图片

你可能感兴趣的:(vue,3.0和2.0区别,vue,init,webpack,卡住,vue,render函数,vue,数组赋值,vue钩子函数)