vue生命周期详解简书,简述vue生命周期的含义
在实际的项目开发过程中,我们会非常频繁地处理Vue组件的生命周期。接下来,我们将从源代码的角度来看这些生命周期的钩子函数是如何执行的。有需要的可以参考下面这篇文章。
目录
1、创建前创建2、挂载前挂载3、更新前更新4、销毁前销毁5、激活停用前言:
每个Vue实例在创建之前都要经历一系列初始化过程。例如,您需要设置数据监控、编译模板、将实例挂载到DOM,以及在数据发生变化时更新DOM。同时,在这个过程中还会运行一些被称为生命周期钩子的函数,让用户有机会在一些特定的场景下添加自己的代码。
源代码中最终执行生命周期的函数都调用callHook方法,它的定义在 src/core/instance/lifecycle 中:。
导出函数callHook (vm: Component,hook: string) {
//#7573调用生命周期挂钩时禁用dep收集
pushTarget()
常量处理程序=虚拟机。$ options[挂钩]
if(处理程序){
for(设i=0,j=handlers.lengthI j;i ) {
尝试{
经手人[我]。呼叫(虚拟机)
} catch (e) {
handleError(e,vm,` ${hook} hook `)
}
}
}
如果(vm。_hasHookEvent) {
vm。$emit(hook: hook )
}
popTarget()
}
callHook函数的逻辑非常简单。根据传入的字符串钩子,获取vm对应的回调函数数组。$options[hook],然后遍历执行。执行时,以vm为函数执行的上下文。
1、beforeCreate created
在Vue的实例化过程中,create和created函数都在_init方法中执行,其定义在src/core/instance/init.js中:
Vue.prototype._init=function(选项?对象){
//.
初始生命周期(虚拟机)
初始化事件(虚拟机)
初始化渲染(虚拟机)
callHook(虚拟机,“创建前”)
initInjections(vm) //在数据/属性之前解析注入
初始化状态(虚拟机)
initProvide(vm) //在数据/属性之后解析提供
callHook(虚拟机,“已创建”)
//.
}
可以看到beforeCreate和created的钩子调用在initState之前和之后。initState的功能是初始化属性,如props、data、methods、watch、computed等。之后我们再详细分析。显然,beforeCreate的hook函数无法获取props和data中定义的值,也无法调用方法中定义的函数。
当这两个钩子函数被执行时,DOM没有被渲染,所以我们也不能访问DOM。一般来说,如果一个组件在加载时需要和后端交互,可以在这两个钩子函数中执行。如果需要访问道具、数据等数据,需要使用创建的hook函数。后面介绍vue-router和vuex的时候会发现,两者都是混合了beforeCreatd hook函数的。
2、beforeMount mounted
顾名思义,beforeMount钩子函数发生在Mount中,也就是DOM挂载之前,它的调用时间在mountComponent函数中,这个函数是在src/core/instance/lifecycle.js中定义的:
导出函数mountComponent(
vm:组件,
el:元素,
补水?布尔型
):组件{
vm。$el=el
//.
callHook(虚拟机,“装载前”)
让更新组件
/*伊斯坦布尔忽略if */
if (process.env.NODE_ENV!==生产配置.性能标志){
updateComponent=()={
const name=vm。_name
const id=vm。_uid
const start tag=` vue-perf-start:$ { id } `
const end tag=` vue-perf-end:$ { id } `
标记(开始标记)
const vnode=vm。_render()
标记(结束标记)
measure(`vue ${name} render `,startTag,endTag)
标记(开始标记)
vm。_更新(虚拟节点,补水)
标记(结束标记)
测量(` vue ${name} patch `,startTag,endTag)
}
}否则{
updateComponent=()={
vm。_更新(虚拟机。_render(),补水)
}
}
//我们把这个设置为vm。观察器构造函数中的观察器(_ w)
//由于观察器的初始补丁可能调用$forceUpdate(例如在儿童内部
//组件的挂载钩子),它依赖于虚拟机.已经定义了_观察者
新观察器(虚拟机、更新组件、noop 、{
之前(){
如果(虚拟机._isMounted) {
呼叫挂钩(虚拟机,"更新前")
}
}
},true /* isRenderWatcher */)
补水=假
//手动装入实例,调用装入自身
//在其插入的挂钩中为呈现创建的子组件调用安装好的
如果(虚拟机.$vnode==null) {
虚拟机._isMounted=true
调用挂钩(虚拟机,"已安装")
}
返回虚拟机
}
在执行虚拟机.渲染()函数渲染虚拟节点之前,执行了即将挂载钩子函数,在执行完虚拟机.更新()把虚拟节点补丁到真实数字正射影像图后,执行mouted钩子。注意,这里对mouted钩子函数执行有一个判断逻辑,虚拟机.$vnode如果为空,则表明这不是一次组件的初始化过程,而是我们通过外部新某视频剪辑软件初始化过程。那么对于组件,它的安装好的时机在哪儿呢?
组件的虚拟节点补丁到数字正射影像图后,会执行invokeInsertHook函数,把insertedVnodeQueue里保存的钩子函数依次执行一遍,它的定义在src/core/vdom/patch.js中:
函数invokeInsertHook (vnode,queue,initial) {
//延迟组件根节点的插入挂钩,在
//元素确实被插入
if(为真(初始)isDef(vnode。父级)){
vnode。父母。数据。挂起插入=队列
}否则{
对于(设I=0;我队列长度;i) {
队列[I]。数据。钩子。插入(队列[I])
}
}
}
该函数会执行插入这个钩子函数,对于组件而言,插入钩子函数的定义在src/core/vdom/create-component射流研究…中的componentVNodeHooks中:
const componentVNodeHooks={
//.
insert(vnode:MountedComponentVNode){
const { context,componentInstance }=vnode
如果(!组件实例. isMounted) {
组件实例. isMounted=true
callHook(组件实例,"已安装")
}
//.
},
}
我们可以看到,每个子组件都是在这个钩子函数中执行mouted钩子函数,并且我们之前分析过,插入的VnodeQueue的添加顺序是先子后父,所以对于同步渲染的子组件而言,已安装钩子函数的执行顺序也是先子后父。
3、beforeUpdate updated
顾名思义,更新前和更新的钩子函数执行时机都应该是在数据更新的时候,到目前为止,我们还没有分析某视频剪辑软件的数据双向绑定、更新相关,下一章我会详细介绍这个过程。
更新前的执行时机是在渲染看守人的以前函数中
导出函数安装组件(
虚拟机:组件,
el:元素,
补水?布尔型
):组件{
//.
//我们把这个设置为虚拟机.观察器构造函数中的观察器(_ w)
//由于观察器的初始补丁可能调用$forceUpdate(例如在儿童内部
//组件的挂载钩子),它依赖于虚拟机.已经定义了_观察者
新观察器(虚拟机、更新组件、noop 、{
之前(){
如果(虚拟机._isMounted) {
呼叫挂钩(虚拟机,"更新前")
}
}
},true /* isRenderWatcher */)
//.
}
注意这里有个判断,也就是在组件已经安装好的之后,才会去调用这个钩子函数。
更新的执行时机是在flushSchedulerQueue函数调用的时候,它的定义在src/core/observer/scheduler.js中:
函数flushSchedulerQueue () {
//.
//获取到更新队列
callUpdatedHooks(updatedQueue)
}
函数callUpdatedHooks(队列){
设i=队列长度
while (i - ) {
常量观察器=队列[i]
const vm=watcher.vm
如果(虚拟机._watcher===观察程序虚拟机._isMounted) {
呼叫挂钩(虚拟机,"已更新")
}
}
}
flushSchedulerQueue函数我们之后会详细介绍,可以先大概了解一下,更新队列是更新了的沃特斯彻数组,那么在callUpdatedHooks函数中,它对这些数组做遍历,只有满足当前看守人为虚拟机._观察者以及组件已经安装好的这两个条件,才会执行更新钩子函数。
我们之前提过,在组件增加的过程中,会实例化一个渲染的看守人去监听伏特计上的数据变化重新渲染,这断逻辑发生在安装组件函数执行的时候:
导出函数安装组件(
虚拟机:组件,
el:元素,
补水?布尔型
):组件{
//.
//这里是简写
让updateComponent=()={
虚拟机._更新(虚拟机. render(),补水)
}
新观察器(虚拟机、更新组件、noop 、{
之前(){
如果(虚拟机._isMounted) {
呼叫挂钩(虚拟机,"更新前")
}
}
},true /* isRenderWatcher */)
//.
}
那么在实例化看守人的过程中,在它的构造函数里会判断isRenderWatcher,接着把当前看守人的实例赋值给虚拟机._watcher,定义在src/core/observer/watcher.js中:
导出默认类观察器{
//.
构造器(
虚拟机:组件,
expOrFn: string Function,
cb:功能,
选项?对象,
isRenderWatcher?布尔型
) {
this.vm=vm
if (isRenderWatcher) {
虚拟机._watcher=这
}
虚拟机._watchers.push(本)
//.
}
}
同时,还把当前沃特斯彻实例推到虚拟机.观察者中,虚拟机.看守人是专门用来监听伏特计上数据变化然后重新渲染的,所以它是一个渲染相关的观察者,因此在callUpdatedHooks函数中,只有虚拟机._观察者的回调执行完毕后,才会执行更新钩子函数。
4、beforeDestroy destroyed
顾名思义,销毁前和破坏钩子函数的执行时机在组件销毁的阶段,组件的销毁过程之后会详细介绍,最终会调用$销毁方法,它的定义在src/核心/实例/生命周期。射流研究…中:
vue。原型。$ destroy=function(){
常量vm:组件=这个
如果(虚拟机._ isbeingdestored){
返回
}
呼叫挂钩(虚拟机,"销毁前")
虚拟机._ isBeingDestroyed=true
//从父代中移除自身
const parent=vm .$parent
如果(家长!父母. isBeingDestroyed!虚拟机.$options.abstract) {
移除(父$儿童,vm)
}
//拆卸观察器
如果(虚拟机._watcher) {
虚拟机._watcher.teardown()
}
设i=vm ._观察者。长度
while (i - ) {
虚拟机._watchers[i].拆卸()
}
//从数据鄂毕河(Ob)中删除引用
//冻结的对象可能没有观察者。
如果(虚拟机._data .__ob__) {
虚拟机._data .__ob__ .虚拟机计数-
}
//调用最后一个钩子.
虚拟机._isDestroyed=true
//调用当前呈现树上的销毁挂钩
虚拟机.__补丁_ _(虚拟机. vnode,null)
//火毁钩
呼叫挂钩(虚拟机,"已销毁")
//关闭所有实例侦听器。
虚拟机.$off()
//删除__vue__引用
如果(虚拟机.$el) {
虚拟机.亿美元.__vue__=null
}
//释放循环引用(#6759)
如果(虚拟机.$vnode) {
虚拟机.$vnode.parent=null
}
}
销毁前钩子函数的执行时机是在破坏函数执行最开始的地方,接着执行了一系列的销毁动作,包括从父母的孩子们中删掉自身,删除观察者,当前渲染的虚拟节点执行销毁钩子函数等,执行完毕后再调用破坏钩子函数。
在$销毁的执行过程中,它又会执行虚拟机.补丁(虚拟机._vnode,null)触发它子组件的销毁钩子函数,这样一层层的递归调用,所以破坏钩子函数执行顺序是先子后父,和安装好的过程一样。
5、activated deactivated
激活的和无效的钩子函数是专门为点火电极组件定制的钩子,我们会在介绍点火电极组件的时候详细介绍,这里先留个悬念。
总结:
本节主要介绍Vue生命周期中各个钩子函数的执行时序和顺序。通过分析我们知道,在创建的钩子函数中可以访问数据,在挂载的钩子函数中可以访问DOM,在销毁钩子函数中可以进行定时器销毁。了解它们有助于我们在适当的生命周期做不同的事情。
这篇带你了解Vue生命周期的文章到此结束。有关Vue生命周期的更多信息,请搜索我们以前的文章或继续浏览下面的相关文章。希望大家以后能多多支持我们!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。