Vue 生命周期 + nextTick【vue 知识汇点2】

2,274 阅读1分钟

vue 生命周期

单个 vue 的生命周期

beforeCreate 和 created

beforeCreate 和 created 函数都是在实例化 Vue 的阶段,在 _init 方法中执行,它的定义在 src/core/instance/init.js中:

vue.prototype._init = function() {
	initLifecycle(vm);
    initEvents(vm);
    initRender(vm);
    callHook(vm, 'beforeCreate') /// beforeCreate 的钩子函数中就不能获取到 props、data、computed、methods
    initInjections(vm)
    initState(vm) // 初始化 props、data、methods、watch、computed
    initProvide(vm)
    callHook(vm, 'created') // 没有渲染 DOM,所以不能访问 DOM。不能访问到 $el 属性,$ref为空数组
}

beforeMount 和 mounted

在执行 vm._render() 函数渲染 VNode 之前(也就是挂载开始之前),执行了 beforeMount 钩子函数,beforeMount 之前,会找到对应的 template,编译成 render 函数。

在执行完 vm._update() 把 VNode patch 到真实的 DOM 后,执行 mounted 钩子,将实例挂载到 DOM 上,此时可以通过 DOM API 获取到 DOM 节点,$ref 可以访问。

组件mount的过程中,会实例化 watcher 去监听 vm 上的数据变化重新渲染。

beforeUpdate 和 updated

beforeUpdate 和 updated 的钩子函数执行时机都应该是在数据更新的时候,

beforeUpdate 的执行时机是在渲染 Watcher 的 before 函数中,发生在虚拟 DOM 打补丁之前。

update 的执行时机是 flushSchedulerQueue 函数调用的时候,在虚拟 DOM 重新渲染和打补丁之后调用,组件 DOM 已经更新,可执行依赖于 DOM 的操作。⚠️注意:要避免操作数据,可能会陷入死循环

beforeDestory 和 destroyed

beforeDestory:实例销毁之前调用,在这一步,实例依然可用,this 仍能获取到实例。

destoryed: 实例销毁后调用,调用后,vue 实例指示的定西都会解绑定,所有的事件监听器都会被移除,所有子实例也会被销毁。

Vue 父子组件的生命周期

加载渲染过程

父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created ->
子beforeMount -> 子mounted -> 父mounted

⚠️注意:mounted 不会承诺所有的子组件都一起被挂载,如果希望整个视图都渲染完毕,可以使用 vm.$nextTick 代替 mounted

更新过程

父beforeUpdate -> 子bedoreUpdate ->子updated -> 父updated

销毁过程

父beforeDestory -> 子beoreDestory -> 子destoryed -> 父destoryed

nextTick

Vue 中的 $nextTick

Vue 官方对 nextTick 这个 API 的描述是:在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后立即调用这个方法,获取更新后的 DOM。

Vue 异步执行 DOM 更新,只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一 Event Loop 中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算机和 DOM 操作非常重要。然后,在下一个的事件循环‘tick’中,vue 刷新队列并执行时机工作。

因为数据的变化到DOM的更新渲染是一个异步过程,发生在下一个 tick,所以如果我们的某些方法去依赖了数据修改后的 DOM 变化,我们就必须在 nextTick 后执行。

应用场景

  1. Vue 生命周期的 created 钩子函数进行 DOM 操作时一定要放在 $nextTick 的回调函数里。
  2. 当项目中你想在改变 DOM 元素的数据后,基于新 DOM 做点什么时
  3. 在使用某个第三方插件时,希望在 vue 生成的某些 dom 动态发生变化时,重新应用该插件,也要用这个方

Node.js 中的 process.nextTick

process.nextTick() 方法将回调函数添加到下一个时间点的队列。在js堆栈上的当前操作运行完成之后,以及允许 Event Loop 继续之前,此队列会被完全耗尽。是个微任务