【得物技术】一文读懂 Vue 生命周期
前言
生命周期(Life Cycle)的概念应用很广泛,其基本涵义可以通俗地理解为“从摇篮到坟墓”(Cradle-to-Grave)的整个过程。
比如人,生老病死,比如石头,沉淀风化,最后成为泥土。
在使用Vue开发过程中经常会接触到生命周期的问题,每个钩子函数都做了什么,应用场景是什么。
今天就来聊一聊Vue的生命周期。
Vue生命周期
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。
同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
每个Vue实例在被创建时都要经过一系列的过程:
开始创建 -> 初始化数据 -> 编译模板 -> 挂载DOM-渲染 -> 更新-渲染 -> 销毁
通俗来讲,就是Vue实例从创建到销毁的过程,这个过程被称为Vue 的生命周期。
生命周期钩子
Vue 所有的功能的实现都是围绕其生命周期进行的,在生命周期的不同阶段调用对应的钩子函数可以实现组件数据管理和DOM渲染两大重要功能。
生命周期中有多个事件钩子,在控制整个vue实例的过程时更容易形成好的逻辑。
根据每个阶段触发的钩子函数,我们可以相应的做一些操作,如获取后端接口数据、监听事件、执行事件、执行定时器、移除事件、清理定时器等等。
Vue的生命周期可以简单分为四个阶段:
创建阶段,挂载阶段,运行阶段,销毁阶段
每个阶段都有两个生命周期钩子函数:
创建阶段--beforeCreate,created
挂载阶段--beforeMount,mounted
运行阶段--beforeUpdate,updated
销毁阶段--beforeDestroy,destroyed
什么是钩子函数?
钩子函数可以简单理解为是一种系统在不同的阶断自动执行、用户无须干预的函数。
那么,钩子函数和回调函数有什么区别吗?
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。
回调函数其实就是调用者把回调函数的函数指针传递给调用函数,当调用函数执行完毕时,通过函数指针来调用回调函数。
回调函数和钩子函数的区别根本上是:
钩子函数在捕获消息的第一时间就执行,而回调函数是捕获结束时,最后一个被执行的。
打个比方:
钩子函数可以看做是一个房间里的监控摄像头监控着每一个进入的人的面部特征,识别出了符合条件的人就触发警告。
回调函数可以看做是在一片地区埋了许许多多的地雷,一旦踩中了某个地雷(触发事件),地雷就会爆炸。
可以简单的理解为:
钩子函数是事件被动的监听,一旦条件触发就执行;回调函数是主动事件,执行函数体内容。
所有的生命周期钩子自动绑定this上下文到实例中,因此可以访问数据并对属性和方法进行运算。箭头函数没有this,因此不能使用箭头函数来定义一个生命周期方法。
简单了解钩子函数之后,我们再来深入探究下 Vue 的生命周期。
生命周期探究
生命周期图示
首先看上图的官方生命周期示意,它已经大概的告诉了我们,每个阶段做了什么:
生命周期钩子函数的执行顺序也就像上面这样,相信大家从命名也能猜出来,接下来我们来详细分析一下。
创建阶段
创建阶段可以看做一个vue实例生命的开始,可以把这一阶段比作组件从受精卵到胚胎的过程,这个阶段 vue组件开始初始化,vue开始观察数据,这个阶段有 beforeCreate和 created两个生命周期钩子函数。
beforeCreate
beforeCreate是new Vue()之后触发的第一个钩子,此时 data、methods、computed以及watch上的数据和方法还未初始化,都不能被访问。
created
created在实例创建完成后被立即调用,此时已完成以下的配置:数据观测 (data observer),property 和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el property 目前尚不可用,也就是可以使用数据,更改数据,在这里更改数据不会触发updated函数。
可以做什么:
data 和 methods 都已经被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据,最早可以在这个阶段中操作。
无法与Dom进行交互,如果非要想,可以通过vm.$nextTick来访问Dom。
异步数据的请求适合在created 的钩子中使用,例如数据初始化。
挂载阶段
这个阶段是vue实例的出生阶段,这个阶段将实现 DOM 的挂载,这标志着我们可以在浏览器里中看到页面了。
beforeMount
beforeMount发生在挂载之前,在这之前 template 模板已导入渲染函数编译。此时虚拟Dom已经创建完成,即将开始渲染。在这一阶段也可以对数据进行更改,不会触发updated。
执行到这个钩子的时候,在内存中已经编译好了模板了,但是还没有挂载到页面中,此时,页面还是旧的。
mounted
mounted在挂载完成后发生,此时真实的Dom挂载完毕,数据完成双向绑定,可以访问到Dom节点,使用$refs属性对Dom进行操作。
执行到这个钩子的时候,就表示vue实例已经初始化完成了。此时组件脱离了创建阶段,进入到了运行阶段。 如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行。
运行阶段
vue实例不可能一直保持不变,就像人随着年龄的增长,形体会发生变化。当vue实例中的数据发生改变时,DOM 也会发生变化。
beforeUpdate
beforeUpdate发生在更新之前,也就是响应式数据发生更新,虚拟dom重新渲染之前被触发,你可以在当前阶段进行更改数据,不会造成重新渲染,但会再次触发当前钩子函数。
updated
updated发生在更新完成之后,此时 Dom 已经更新。现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,最好使用计算属性或 watcher取而代之。最好不要在此期间更改数据,因为这可能会导致无限循环的更新。
销毁阶段
vue实例的消亡阶段。实例还可以被使用,直到destroyed(),我们可以最后做一些想做的事情。
beforeDestroy
beforeDestroy发生在实例销毁之前,在这期间实例和所有函数完全可以被使用,我们可以在这时进行善后收尾工作,可以执行资源管理、删除变量和清理组件,比如清除计时器。
destroyed
这是 vue 生命周期的最后阶段,这个时候只剩下了dom空壳。在这个阶段组件已被拆解,数据绑定被卸除,事件监听器被移除,所有子实例也统统被销毁。
总结
为了便于记忆,将这些内容总结成一张表格。
应用场景
结论
本文主要介绍了 Vue 生命周期中各个钩子函数的执行时机以及顺序,通过分析,我们知道了如在 created 钩子函数中可以访问到数据,在 mounted 钩子函数中可以访问到 DOM,在 destroy 钩子函数中可以做一些定时器销毁工作,了解它们有利于我们在合适的生命周期去做不同的事情。
END
文/Miki
搜索【得物技术】,就能找到我。
版权声明: 本文为 InfoQ 作者【得物技术】的原创文章。
原文链接:【http://xie.infoq.cn/article/488658c52844960dbe0148a20】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论