一、什么是生命周期?
Vue 实例从创建 到销毁 的整个过程,称为生命周期。
在这个过程中,Vue 会在特定阶段自动调用一些函数,这些函数就是生命周期钩子(Lifecycle Hooks)。
你可以把它们理解为"生命阶段的回调函数",在合适的时机执行特定逻辑。
二、Vue 2 生命周期图谱(经典八阶段)
以下是 Vue 2 的生命周期流程图(建议配图):
beforeCreate
↓
created ←←←←← (可发起请求)
↓
beforeMount
↓
mounted ←←←←← (DOM 可访问,常用)
↓
beforeUpdate
↓
updated
↓
beforeDestroy
↓
destroyed
✅ 红色箭头 表示组件可能被销毁后重新创建(如
v-if
切换)。
1. beforeCreate
- 触发时机:实例初始化之后,数据观测 (data observer) 和事件配置之前。
- 能做什么 :几乎不能做任何事,
data
、methods
还未初始化。 - 使用场景:极少使用。
javascript
beforeCreate() {
console.log('beforeCreate: ', this.message) // undefined
}
2. created
- 触发时机:实例创建完成,数据观测、属性和方法运算已完成。
- 能做什么 :
- 访问
data
、methods
- 发起 Ajax 请求
- 设置定时器(注意清理)
- 访问
- 不能做什么 :访问 DOM(
$el
为undefined
)
javascript
created() {
console.log('created: ', this.message) // 正常输出
this.fetchData() // ✅ 推荐在此发起请求
}
✅ 最佳实践:数据初始化、异步请求。
3. beforeMount
- 触发时机:模板编译完成,但尚未挂载到 DOM。
- 能做什么 :很少使用,此时
$el
仍不可用。 - 注意:服务端渲染(SSR)不会调用此钩子。
javascript
beforeMount() {
console.log('beforeMount: ', this.$el) // undefined
}
4. mounted
- 触发时机 :实例挂载到 DOM 后,
$el
被新创建的vm.$el
替换。 - 能做什么 :
- 操作 DOM(如初始化第三方库:Swiper、ECharts)
- 访问
$refs
- 开始定时器
- 重要 :组件已"可见",是最常用的钩子之一。
javascript
mounted() {
console.log('mounted: ', this.$el) // 可访问 DOM
this.initChart() // 初始化图表
this.timer = setInterval(() => {
// 轮询
}, 5000)
}
✅ 最佳实践:DOM 操作、第三方库初始化、定时器启动。
5. beforeUpdate
- 触发时机:数据更新时,虚拟 DOM 重新渲染之前。
- 能做什么:获取更新前的 DOM 状态。
- 注意:不要在此修改状态,否则可能造成无限循环。
javascript
beforeUpdate() {
console.log('视图更新前,数据是:', this.message)
}
6. updated
- 触发时机:数据更新后,虚拟 DOM 重新渲染并应用到 DOM。
- 能做什么 :
- DOM 操作(依赖更新后的 DOM)
- 避免在此发起状态更新,可能造成循环
- 注意:子组件可能尚未更新。
javascript
updated() {
console.log('视图已更新')
// 可操作更新后的 DOM
}
⚠️ 避免 在
updated
中修改data
,否则会再次触发更新。
7. beforeDestroy
(Vue 2)/ beforeUnmount
(Vue 3)
- 触发时机:实例销毁前,实例仍完全可用。
- 能做什么 :
- 清理定时器
- 移除事件监听
- 解除第三方库绑定
- 必须做:防止内存泄漏!
javascript
beforeDestroy() {
clearInterval(this.timer)
window.removeEventListener('resize', this.onResize)
this.$refs.chart.dispose() // 如 ECharts
}
✅ 最佳实践:资源清理,必做!
8. destroyed
(Vue 2)/ unmounted
(Vue 3)
- 触发时机:实例销毁后,所有绑定和监听器被移除。
- 能做什么:很少使用,实例已不可用。
javascript
destroyed() {
console.log('组件已销毁')
}
三、Vue 3 生命周期的变化
Vue 3 中,部分生命周期钩子名称更新,以与 Composition API 保持一致:
Vue 2 | Vue 3 |
---|---|
beforeDestroy |
beforeUnmount |
destroyed |
unmounted |
📌 其他钩子名称不变。
Composition API 中的生命周期钩子
在 setup()
中,使用 onXxx
函数注册生命周期钩子:
html
<script>
import {
onMounted,
onUpdated,
onUnmounted
} from 'vue'
export default {
setup() {
onMounted(() => {
console.log('组件已挂载')
})
onUpdated(() => {
console.log('组件已更新')
})
onUnmounted(() => {
console.log('组件已卸载')
// 清理资源
})
return {}
}
}
</script>
✅ 所有
onXxx
函数必须在setup()
或<script setup>
中调用。
四、生命周期实战应用场景
1. 发起 API 请求
javascript
created() {
this.loading = true
fetch('/api/users')
.then(res => res.json())
.then(data => {
this.users = data
})
.finally(() => {
this.loading = false
})
}
✅
created
是发起请求的最佳时机。
2. 初始化第三方库
javascript
mounted() {
this.chart = new Chart(this.$refs.canvas, {
type: 'bar',
data: this.chartData
})
}
3. 清理资源(防内存泄漏)
javascript
export default {
data() {
return {
timer: null
}
},
mounted() {
this.timer = setInterval(() => {
this.updateTime()
}, 1000)
},
beforeUnmount() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
}
}
✅ 必须在
beforeUnmount
中清理!
4. 监听窗口事件
javascript
mounted() {
window.addEventListener('resize', this.handleResize)
},
beforeUnmount() {
window.removeEventListener('resize', this.handleResize)
}
五、常见问题与注意事项
❓ created
和 mounted
有什么区别?
阶段 | 能访问数据 | 能访问 DOM |
---|---|---|
created |
✅ | ❌ |
mounted |
✅ | ✅ |
✅ 数据请求放
created
,DOM 操作放mounted
。
❓ 为什么不能在 beforeCreate
中访问 data
?
因为此时 Vue 还未完成数据观测(Observer)的初始化。
❓ updated
会频繁触发吗?
会!每次数据更新 都会触发 updated
,避免在此执行昂贵操作。
❓ 子组件的生命周期顺序?
父组件 beforeCreate
→ created
→ beforeMount
↓
子组件 beforeCreate
→ created
→ mounted
↓
父组件 mounted
✅ 先子后父。
六、总结:生命周期钩子使用指南
钩子 | 是否常用 | 典型用途 |
---|---|---|
created |
✅ | 数据初始化、API 请求 |
mounted |
✅ | DOM 操作、第三方库初始化 |
beforeUpdate |
⚠️ | 获取更新前状态 |
updated |
⚠️ | 依赖更新后 DOM 的操作 |
beforeUnmount |
✅ | 清理定时器、事件监听 |
unmounted |
⚠️ | 组件销毁后通知 |
📌 核心原则:在合适的时机做合适的事。
七、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!