详细一些的vue生命周期
如果你和我一样,以前对vue生命周期的理解仅限于生命周期钩子,那么本文可以让我们更深入一层,理解vue在生命周期各个阶段所做的事,对我们对vue的理解和使用很有好处。
(1)通过new Vue()创建新的vue实例
不管页面还是组件,都是一个个vue实例。一个vue应用,其实就是一个个vue实例的嵌套。
(2)初始化生命周期和事件监听
vue实例在生命周期中,会用一些内部变量来标志生命周期的当前阶段,比如_isMounted、_isDestroyed等,这些标志对于vue的内部运行很重要,决定了在什么时候做什么事。
vue会绑定事件监听函数,包括组件自身的事件监听,和父组件向子组件传递的事件监听。
(3)beforeCreate钩子
此时还无法访问props、data、computed、watch、methods。
(4)初始化状态
初始化props、data、computed、watch、methods,vue会在此时循环遍历props、data、computed的每一个属性,用Object.defineProperty()把属性转换为getter、setter,这是vue2实现响应式的基础。
(5)created钩子
此时props、data、computed、watch、methods已经初始化完成,可以通过this来调用了。如果想在进入页面后马上做一些操作,此时是最好的选择,我们一般都在此时调用api拉取数据。
(6)开始挂载
如果el属性存在,则执行$mount()开始挂载。否则,等到vm.$mount()被调用时,再开始挂载。
(7)beforeMount钩子
this.$el开始可以访问,不过此时获取到的是vue实例挂载前的DOM对象。
(8)模板编译
检查el、templete、render三个属性,如果render存在,则直接作为render函数进入下一步,否则如果templete存在,则把它编译成render函数,否则如果el存在,则以el的outerHTML作为模板编译成render函数。总之,这一步的目的就是得到一个render函数,也就是渲染函数。每一个vue组件都有自己的render函数。
(9)生成虚拟DOM
执行render函数,得到虚拟DOM。
(10)渲染
用vue实例的数据填充虚拟DOM,把虚拟DOM(是一个对象)渲染为真实的DOM(就是网页中的DOM元素)。
(11)挂载
把真实的DOM挂载到页面中。
如果有el属性,则替换掉el的outerHTML。如果没有,则会等到$mount()被调用时再挂载(参数可以是css选择器或者DOM对象),同样替换掉目标元素的outerHTML,不管它里面有什么内容。如果没有调用$mount(),则DOM对象会保持在内存中,你可以通过this.$el获取到它,然后手动插入到页面中。
(12)mounted钩子
此时DOM已经正式挂载到页面中,可以通过this.$el访问到最终的DOM对象。需要访问DOM的操作可以在此时进行,常见于一些第三方库。
(13)beforeUpdate钩子
当模板的依赖数据发生变化时,beforeUpdate钩子会被触发,模板开始重更新渲染。
(14)diffing
生成新的虚拟DOM,和旧的虚拟DOM进行差异化比较,这个过程叫“diffing”。
(15)patching
基于上一步的结果,尽可能少的对真实DOM做出修改,这个过程叫“patching”。
(16)updated钩子
在DOM更新完成后,updated钩子被触发,此时,你可以访问到更新后的DOM。
我们更常用的是在代码中,修改data数据后想要马上访问到更新后的DOM,此时可以把代码写在this.$nextTick()的参数函数里。
(17)beforeDestroy钩子
vue实例即将被销毁,但此时实例仍然完全可用。
我们一般在此时做一些清理工作,比如:移除全局的事件监听(比如window的resize事件)、清理setTimeout和setInterval、释放一些资源(比如websocket连接)、保存组件的状态(比如滚动的位置、复杂的表单输入)。
(18)destroyed钩子
vue实例已经被销毁,所有的事件监听已经被移除,所有的子实例也已经被销毁。
如果该实例有子组件,子组件的从beforeCreate到mounted将会插入到该实例的beforeMount和mounted之间进行,子组件的beforeDestroy和destroyed则会插入到该实例的beforeDestroy和destroyed之间进行。至于beforeUpdate和updated,vue组件的更新基于依赖追踪,父组件和子组件的更新没有必然的联系。可以看一下我的上一篇文章:《vue的响应式原理:依赖追踪》。
有子组件的实例生命周期如下:
(1)beforeCreate
(2)created
(3)beforeMount
(4)子组件beforeCreate
(5)子组件created
(6)子组件beforeMount
(7)子组件mounted
(8)mounted
(9)beforeDestroy
(10)子组件beforeDestroy
(11)子组件destroyed
(12)destroyed
这样的设计,保证了父组件挂载完成时,子组件已全部挂载,父组件销毁时,子组件已全部销毁,确保了它们之间逻辑上的所属关系。
本人水平非常有限,写作主要是为了把自己学过的东西捋清楚。如有错误,还请指正,感激不尽。