以下是 Vue 生命周期每一步中 Vue 本身的核心行为,
1. beforeCreate
- Vue 内部行为:
- 初始化生命周期状态:设置
_isMounted
、_isDestroyed
等内部标志位。 - 初始化事件系统:创建
_events
对象,用于存储组件的事件监听器。 - 初始化
props
和methods
:解析组件定义的props
和methods
,但尚未绑定到实例。 - 处理依赖注入:解析
inject
选项,从父级组件获取依赖(但未注入到当前实例)。
- 初始化生命周期状态:设置
- 用户可感知的结果:
data
、computed
、methods
均不可用。- 无法操作 DOM(此时模板尚未编译)。
2. created
- Vue 内部行为:
- 数据响应式化:通过
Object.defineProperty
(Vue 2)或Proxy
(Vue 3)将data
转换为响应式对象。 - 初始化计算属性:为
computed
创建Watcher
,建立依赖关系。 - 初始化侦听器:为
watch
选项创建Watcher
,监听数据变化。 - 完成依赖注入:将父级提供的
provide
值注入到当前实例的inject
。
- 数据响应式化:通过
- 用户可感知的结果:
- 可访问
data
、computed
、methods
。 - 模板未编译,DOM 未渲染。
- 可访问
3. beforeMount
- Vue 内部行为:
- 编译模板:若未提供
render
函数,将template
编译为render
函数(涉及 AST 解析、优化、代码生成)。 - 生成虚拟 DOM:首次调用
render
函数生成虚拟 DOM(VNode 树)。 - 准备挂载:创建
$el
占位符(一个空的 DOM 节点),但未插入页面。
- 编译模板:若未提供
- 用户可感知的结果:
- 虚拟 DOM 已生成,但真实 DOM 未更新。
4. mounted
- Vue 内部行为:
- 挂载 DOM:通过
patch
算法将虚拟 DOM 转换为真实 DOM,并替换$el
占位符。 - 建立响应式关联:为模板中的指令(如
v-model
)和插值表达式创建Watcher
,绑定数据与视图。 - 触发子组件挂载:递归挂载子组件(子组件的
mounted
会在父组件之前执行)。
- 挂载 DOM:通过
- 用户可感知的结果:
- DOM 已渲染完成,可通过
this.$el
或ref
操作 DOM。 - 子组件已挂载。
- DOM 已渲染完成,可通过
5. beforeUpdate
- 触发条件:响应式数据变化,且变化会影响视图。
- Vue 内部行为:
- 生成新虚拟 DOM:重新调用
render
函数生成新的 VNode 树。 - Diff 算法准备:对比新旧 VNode 树,标记需要更新的节点。
- 生成新虚拟 DOM:重新调用
- 用户可感知的结果:
- 数据已更新,但视图未重新渲染。
6. updated
- Vue 内部行为:
- 更新真实 DOM:根据 Diff 结果,通过
patch
函数高效更新真实 DOM。 - 清理旧节点:移除不再需要的 DOM 节点和关联的
Watcher
。
- 更新真实 DOM:根据 Diff 结果,通过
- 用户注意事项:
- 避免在此钩子中修改数据,可能导致无限循环更新。
7. beforeDestroy
- Vue 内部行为:
- 解除依赖:移除所有
Watcher
(包括计算属性、侦听器、模板中的依赖)。 - 销毁子组件:递归调用子组件的销毁逻辑。
- 清理事件监听:移除组件内所有事件监听器(包括自定义事件和原生 DOM 事件)。
- 解除依赖:移除所有
- 用户可感知的结果:
- 组件实例仍存在,但即将销毁。
8. destroyed
- Vue 内部行为:
- 移除 DOM:从父 DOM 节点中移除组件的根元素(
$el
)。 - 释放内存:解除所有响应式数据的引用,触发 GC 回收内存。
- 移除 DOM:从父 DOM 节点中移除组件的根元素(
- 用户可感知的结果:
- 所有数据、方法、DOM 均不可访问。
生命周期与响应式系统的关系
-
依赖收集(
created
阶段):- 在渲染过程中,模板中的每个插值表达式和指令都会创建一个
Watcher
。 - 当数据被访问时,
Watcher
会订阅数据的Dep
(依赖收集器)。
- 在渲染过程中,模板中的每个插值表达式和指令都会创建一个
-
派发更新(
beforeUpdate
阶段):- 数据修改时,触发
Dep.notify()
,通知所有订阅的Watcher
执行更新。 - 更新过程通过队列异步执行,避免重复渲染。
- 数据修改时,触发
常见误区与最佳实践
-
created
vsmounted
:- 数据初始化:在
created
中请求异步数据(此时 DOM 未渲染,减少白屏时间)。 - DOM 操作:在
mounted
中操作 DOM(如使用第三方库初始化图表)。
- 数据初始化:在
-
避免在
updated
中修改数据:updated() { // 错误!可能导致无限循环 this.count++; }
-
手动清理资源:
beforeDestroy() { // 清除定时器、取消网络请求 clearInterval(this.timer); this.$http.cancelRequest(); }
生命周期流程图(Vue 2/3 通用)
初始化
│
├── beforeCreate → 创建实例,未初始化数据
│
├── created → 数据响应式化,未挂载 DOM
│
├── beforeMount → 编译模板,生成虚拟 DOM
│
├── mounted → DOM 挂载完成
│
├── 数据变化 → beforeUpdate → 生成新虚拟 DOM → updated → DOM 更新
│
└── 销毁实例 → beforeDestroy → 清理资源 → destroyed → 实例销毁