生命周期图示
生命周期钩子函数
状态 | 说明 |
---|---|
beforeCreate(创建前) | 组件实例更被创建,组件属性计算之前,数据对象 data 都为 undefined,未初始化。 |
created(创建后) | 组件实例创建完成,属性已经绑定,数据对象 data 已存在,但 dom 未生成,$el 未存在 |
beforeMount(挂载前) | vue 实例的$el 和 data 都已初始化,挂载之前为虚拟的 dom 节点,data.message 未替换 |
mounted(挂载后) | vue 实例挂载完成,data.message 成功渲染。 |
beforeUpdate(更新前) | 当 data 变化时,会触发 beforeUpdate 方法 |
updated(更新后) | 当 data 变化时,会触发 updated 方法 |
beforeDestroy(销毁前) | 组件销毁之前调用 |
destroyed(销毁后) | 组件销毁之后调用,对 data 的改变不会再触发周期函数,vue 实例已解除事件监听和 dom 绑定,但 dom 结构依然存在 |
beforeCreate 创建前
在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
created 创建后
在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),property 和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el
property 目前尚不可用。
beforeMount 挂载前
在挂载开始之前被调用:相关的 render 函数首次被调用。
mounted 挂载后
实例被挂载后调用,这时 el 被新创建的 vm.$el 替换了。如果根实例挂载到了一个文档内的元素上,当 mounted 被调用时 vm.$el 也在文档内。
注意 mounted 不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick
。
beforeUpdate 更新前
数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。
updated 更新后
由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。
注意 updated 不会保证所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以在 updated 里使用 vm.$nextTick
beforeDestroy 销毁前
实例销毁之前调用。在这一步,实例仍然完全可用。
destroyed 销毁后
实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。
activated
被 keep-alive 缓存的组件激活时调用。
deactivated
被 keep-alive 缓存的组件停用时调用。
errorCaptured
2.5.0+ 新增
当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。
生命周期解释
new Vue(options) 后
- 将用户提供的 options 与默认 options 合并,初始化 LifeCycle、Events、Render
- 触发 beforeCreate 钩子
- 初始化 Injections、State(包括初始化 props、methods、data(初始化 data 时 调用 Observer.observe 方法添加 Dep 依赖)、computed、watch)、Provide
- 触发 created 钩子
- 触发 beforeMount 钩子
- 对 vm 创建 Watcher 执行 updateComponent 方法,updateComponent方法调用 vm._render 方法生成 VNode,调用 vm._update 把 VNode 渲染成真实的 DOM
- 触发 mounted 钩子
数据 data 变化后
- 初始化 data 时创建的 Observer 通过 Dep 触发了 watcher.update() 方法,watcher.update() 调用 scheduler.queueWatcher() 调用 scheduler.flushSchedulerQueue(),尝试调用 watcher.run()
- 触发 beforeUpdate 钩子(之前已经注册了 Watcher.before)
- watcher 执行 watcher.run 方法,执行 watcher.get 方法,执行 watcher.getter 方法 即 updateComponent 方法,updateComponent 方法调用 vm._render 方法生成 VNode,调用 vm._update 把 VNode 渲染成真实的 DOM
- 再回到 scheduler.flushSchedulerQueue 方法,在所有的 watcher 执行完毕后,触发 updated 钩子
组件销毁时
patch.removeVnodes -> patch.invokeDestroyHook -> destroy -> vm.$destroy ->
- 调用 beforeDestroy 钩子
- 将自身从父组件中移除,移除 watchers
- 调用 destoryed 钩子
- 关闭所有实例监听器
Vue2 与Vue3的生命周期对比
Vue2 | Vue3 |
---|---|
beforeCreate(组件创建之前) | setup(组件创建之前) |
created(组件创建完成) | setup(组件创建完成) |
beforeMount(组件挂载之前) | onBeforeMount(组件挂载之前) |
mounted(组件挂载完成) | onMounted(组件挂载完成) |
beforeUpdate(数据更新,虚拟DOM打补丁之前) | onBeforeUpdate(数据更新,虚拟DOM打补丁之前) |
updated(数据更新,虚拟DOM渲染完成) | onUpdated(数据更新,虚拟DOM渲染完成) |
beforeDestroy(组件销毁之前) | onBeforeUnmount(组件销毁之前) |
destroyed(组件销毁之后) | onUnmounted(组件销毁之后) |
Vue 子组件和父组件执行顺序
加载渲染过程:
- 父组件 beforeCreate
- 父组件 created
- 父组件 beforeMount
- 子组件 beforeCreate
- 子组件 created
- 子组件 beforeMount
- 子组件 mounted
- 父组件 mounted
更新过程:
- 父组件 beforeUpdate
- 子组件 beforeUpdate
- 子组件 updated
- 父组件 updated
销毁过程:
- 父组件 beforeDestroy
- 子组件 beforeDestroy
- 子组件 destroyed
- 父组件 destoryed
异步请求放在哪个生命周期中
我们可以在钩子函数 created、beforeMount、mounted 中进行调用,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。
推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:
- 能更快获取到服务端数据,减少页面加载时间,用户体验更好;
- SSR不支持 beforeMount 、mounted 钩子函数,放在 created 中有助于保持一致性。