Vue生命周期源码分析~

9 篇文章 0 订阅
7 篇文章 3 订阅

Vue实例的生命周期大致可分为四个阶段

  1. 初始哈阶段:为Vue实例上初始化一些属性,事件以及响应式数据
  2. 模板编译阶段:将模板编译成渲染函数
  3. 挂载阶段: 将实例挂载到指定的DOM上,即将模板渲染到真实DOM中
  4. 销毁阶段: 将实例自身从父组件中删除,并取消依赖追踪及事件监听器

初始化阶段:

初始化阶段所做的第一件事就是new Vue()创建一个Vue实例,那么new Vue()的内部都干了上面,我们知道,new关键字在JS中表示从一个类中实例化出一个对象来,由此可见,Vue实例上是一个类,所以new Vue()实例上执行了Vue类的构造函数
初始化阶段所作的工作也可大致分为两个部分:第一部分是new Vue(),也就是创建一个Vue实例,第二部分是为创建好的Vue实例初始化一些事件,属性,响应式数据等。

讲述第一个初始化函数initLifecycle

  • ----- 初始化第一部分initLifecycle: 给实例初始化一些属性,包括以$开头的供用户使用的外部属性,也包括_开头的拱内部使用的内部属性
  • ----- 初始化第二部分initEvents:初始化实例的事件系统,父组件给子组件的注册事件中,把自定义事件传给子组件,在子组件实例化的时候进行初始化,而浏览器原生事件是在父组件中吹。 也就是实例初始化阶段调用的初始化事件函数initEvents实际上初始化的是父组件在模板中使用v-on或者@注册的监听子组件触发的事件。该函数是用来初始化实例的事件系统的。
  • ----- 第四个初始化函数initInjections,该函数是用来初始化实例中的inject选项的,作用:允许一个祖先组件想其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上次游关系成立的时间里始终生效。并且provide选项应该是一个对象或返回一个对象的函数,该对象包含可注入子孙的属性。在该对象中你可以使用ES5 Symbol作为key,但是只在原生支持Symbol和Reflect.ownKeys的环境下可工作
  • inject选项应该是: 一个字符串数组 或 一个对象,对象的key是本地的绑定名。value是可在用的注入内容中搜索用的key或者一个对象。该对象的from属性是在可用的注入呢日中搜索用的key,default属性是降级情况下使用的value
  • 父组件可以使用provide选项给自己的下游子孙组件内注入一些数据,在下游子孙组件中可以使用inject选项来接收这些数据以便为自己使用
  • provide 和 inject选项绑定的数据不是响应式的
  • 总结:该函数是用来初始化inject选项的,
  • ----- 第五个初始化函数initState:是用来初始化实例状态的,data,props,methods,computed,watch选项,我们把这些称为实例的状态选项,也就是说initState函数就是用来初始化这些状态的,

初始化computed: 计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。
初始化watch:可以用来侦听某个已有的数据,当该数据发生变化执行对应的对调函数,

模板编译阶段

  • 模板编译阶段:模板编译阶段并不是存在于Vue的所有构建版本中,它只存在于完整版本,在只包含运行的时候版本中并不存在改阶段,这是因为当使用vue-loader或者vueify的时候,vue文件内部的模板会在构建的时候预编译成渲染函数,所以是不需要编译的。从而不存在模板编译阶段,由上一步的初始化阶段直接进入下一阶段的挂载阶段。
  • vue基于源码构建的有两个版本,一个是runtime only一个只包含运行是的版本,另一个是runtime+compiler一个同事包含编译器和运行时的- 完整版本,这两个版本的区别仅在于后者包含了一个编译器。
  • 完整版本是包含编译器的,我们可以使用template选项进行模板编写,扁你其会自动将template选项中的模板字符串编译成函数的代码,源码中被的render函数, 如果你需要再客户端编译模板,就需要一个包含编译器的版本
// 需要编译器的版本
new Vue({
  template: '<div>{{ hi }}</div>'
})
  • 只包含运行时的版本: 拥有创建Vue实例,渲染并处理Virtval DOM等功能,基本上就是除去编译器外的完整代码,该版本的适用场景有两种:我们在选项中通过手写render函数去定义渲染过程,这个时候并不需要包含编译器的版本便可完整执行。没有模板编译阶段。
// 不需要编译器
new Vue({
  render (h) {
    return h('div', this.hi)
  }
})

模板编译阶段分析:上文中说了,完整版和只包含运行时版之间的差异主要在于是否有模板编译阶段。而是否有模板编译阶段主要表现在vm.$mount方法的实现上,

  1. 生命周期第二阶段----模板编译阶段:Vue源码构建的两种版本:完整版本和只包含运行时版本,模板编译阶段只存在于完整版中,在只包含运行时版本中不存在该阶段。这是因为在只包含运行时版本中,当使用vue-loader或vueify时,vue文件内部的模板会在构建时预编译成渲染函数,所以是不需要编译的,从而不存在模板编译阶段。
  2. 然后对比了两种版本$mount方法的区别,他们的区别在于$mount方法中是否进行了模板编译,在只包含了运行时版本的$mount方法中获取道DOM元素后直接进入挂载阶段,而在完整版本中$mount方法中是先将模板进行编译,然后回过头来只包含运行时版本的$mount方法进入挂载阶段。
  3. 最后我们知道,分析模板编译阶段其实就是分析完整版的vm.$mount方法实现,我们将完整版的vm.$mount方法源码进行了逐行分析,知道在该阶段所作的工作就是:从用户传入的el选项和template选贤中获取的用户传入的内部或外部模板,然后将获取到的模板编译成渲染函数

挂载阶段

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

挂载阶段分析:在完整版本中 m o u n t 方 法 中 将 模 板 编 译 完 成 之 后 , 会 回 过 头 来 去 调 只 包 含 运 行 版 本 的 mount方法中将模板编译完成之后,会回过头来去调只包含运行版本的 mountmount方法进入挂载阶段。所有要想分析挂载姐u但我们必须要从只包含运行时版本的$mount方法入手
总结:

  • 主要工作时创建Vue实例并用其替换el选项对应的DOM元素,同时还要开启对模板中数据的监控,当数据发生变化时通知其依赖进行更新。
  • 我们将挂在阶段分成两部分进行了分析: 第一部分时将模板渲染到视图上,第二部分是开启对模板中数据的监控,两部分工作都完成以后挂载阶段才算是真正的完成了

销毁阶段

  • 生命周期最后一个阶段:销毁阶段,
  • 实例身上的依赖包含两个部分:一部分是实例自身依赖其它数据,需要将实例自身从其它数据的依赖列表中删除。另一部分是实例内的数据对其它数据的依赖(如用户hi用的$watch创建的依赖)越需要从其它数据的依赖列表中删除实例内数据,所以删除依赖的时候需要将这两部分依赖都删除掉
  • 总结:调用了实例上vm.$destory方法后,实例就进入了销毁阶段,在该阶段所做的主要工作是将当前的Vue实例从其父级实例中删除,取消当前实例上的所有依赖追踪并且移除shi’l上的所有事件监听器,并且对照源码所作的工作都进行了逐行分析
  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值