理解 Vue 生命周期最好的方式是看图。下面用流程图展示 Vue 实例从创建到销毁的完整过程。
┌─────────────────────────────────────┐
│ new Vue() │
└──────────────────┬──────────────────┘
│
▼
┌─────────────────────────────────────┐
│ beforeCreate │
│ 实例初始化之前,data/methods 未定义 │
└──────────────────┬──────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 初始化 data、methods、computed │
│ 建立响应式系统 │
└──────────────────┬──────────────────┘
│
▼
┌─────────────────────────────────────┐
│ created │
│ 实例创建完成,可访问 data/methods │
└──────────────────┬──────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 是否有 el 选项? │
└──────────────────┬──────────────────┘
│
┌────────────────┴────────────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 有 el │ │ 无 el │
└──────┬───────┘ └──────┬───────┘
│ │
│ ▼
│ ┌───────────────────────┐
│ │ 等待 vm.$mount(el) │
│ └───────────┬───────────┘
│ │
└────────────────┬────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 是否有 template 选项? │
└──────────────────┬──────────────────┘
│
┌────────────────┴────────────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 有 template │ │ 无 template │
│ 编译 template │ │ 使用 el HTML │
└──────┬───────┘ └──────┬───────┘
│ │
└────────────────┬────────────────┘
│
▼
┌─────────────────────────────────────┐
│ beforeMount │
│ 模板编译完成,未挂载到 DOM │
└──────────────────┬──────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 创建 vm.$el,替换 el │
│ 挂载到 DOM │
└──────────────────┬──────────────────┘
│
▼
┌─────────────────────────────────────┐
│ mounted │
│ DOM 挂载完成,可访问 $el │
└──────────────────┬──────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 实例已挂载 │
│ 等待数据变化或销毁 │
└──────────────────┬──────────────────┘
│
┌────────────────┴────────────────┐
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ 数据变化 │ │ vm.$destroy() │
└──────────┬──────────┘ └──────────┬──────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ beforeUpdate │ │ beforeDestroy │
│ 数据变化,DOM 未更新 │ │ 实例即将销毁 │
└──────────┬──────────┘ └──────────┬──────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ 重新渲染虚拟 DOM │ │ 移除 watchers │
│ 更新真实 DOM │ │ 移除子组件 │
└──────────┬──────────┘ └──────────┬──────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ updated │ │ destroyed │
│ DOM 更新完成 │ │ 实例已销毁 │
└──────────┬──────────┘ └────────────────┬────┘
│ │
│ ▼
│ ┌─────────────────────┐
│ │ 实例生命周期结束 │
│ └─────────────────────┘
│
└──────────────┐
│
▼
返回等待数据变化状态
创建阶段主要完成实例的初始化工作:
beforeCreate
│
▼
┌─────────────────────────────────┐
│ 初始化事件 & 生命周期 │
│ 初始化 data、props、methods │
│ 建立响应式绑定 │
└─────────────────────────────────┘
│
▼
created
此阶段的特点:
挂载阶段将模板渲染成真实 DOM:
beforeMount
│
▼
┌─────────────────────────────────┐
│ 编译模板为渲染函数 │
│ 生成虚拟 DOM │
│ 创建真实 DOM │
│ 替换页面中的 el 元素 │
└─────────────────────────────────┘
│
▼
mounted
此阶段的特点:
当响应式数据变化时触发更新:
数据变化
│
▼
beforeUpdate
│
▼
┌─────────────────────────────────┐
│ 重新生成虚拟 DOM │
│ 对比新旧虚拟 DOM (diff) │
│ 更新真实 DOM │
└─────────────────────────────────┘
│
▼
updated
此阶段的特点:
实例销毁时触发:
vm.$destroy()
│
▼
beforeDestroy
│
▼
┌─────────────────────────────────┐
│ 移除 watchers │
│ 移除事件监听器 │
│ 销毁子组件 │
└─────────────────────────────────┘
│
▼
destroyed
此阶段的特点:
使用 keep-alive 缓存的组件有额外的生命周期:
┌─────────────────────────────────────────────────┐
│ keep-alive 组件 │
│ │
│ 首次创建:created → mounted → activated │
│ │
│ 切换离开:deactivated │
│ │
│ 再次激活:activated │
│ │
│ 最终销毁:deactivated → beforeDestroy → destroyed │
└─────────────────────────────────────────────────┘
钩子说明:
| 钩子 | 触发时机 |
|---|---|
| activated | 组件被激活时 |
| deactivated | 组件被缓存时 |
Vue.component('tab-content', {
template: '<div>内容</div>',
activated() {
console.log('组件被激活,恢复状态')
this.resumeFromCache()
},
deactivated() {
console.log('组件被缓存,保存状态')
this.saveToCache()
}
})
Vue 还提供了错误捕获钩子:
new Vue({
errorCaptured(err, vm, info) {
console.error('错误:', err)
console.error('组件:', vm)
console.error('信息:', info)
return false
}
})
返回 false 可以阻止错误继续向上传播。