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 后执行。
应用场景
- Vue 生命周期的 created 钩子函数进行 DOM 操作时一定要放在 $nextTick 的回调函数里。
- 当项目中你想在改变 DOM 元素的数据后,基于新 DOM 做点什么时
- 在使用某个第三方插件时,希望在 vue 生成的某些 dom 动态发生变化时,重新应用该插件,也要用这个方
Node.js 中的 process.nextTick
process.nextTick() 方法将回调函数添加到下一个时间点的队列。在js堆栈上的当前操作运行完成之后,以及允许 Event Loop 继续之前,此队列会被完全耗尽。是个微任务。