大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
生命周期
这一课你将能做到
- 说出 Vue 组件从创建到销毁的完整生命周期
- 用
onMounted在组件挂载后执行初始化操作 - 用
onUnmounted清理定时器、事件监听等副作用 - 用
onUpdated在组件更新后执行操作
为什么要学
组件不是「一直活着」的。它有出生(创建)、成长(更新)、死亡(销毁)的过程。很多操作必须在特定阶段执行:比如组件挂载后才能操作 DOM,组件销毁前必须清理定时器,否则内存泄漏。
人话:生命周期就像人的「人生阶段」。出生时要做登记(初始化数据),成年时要工作(更新视图),去世前要立遗嘱(清理资源)。错过阶段就出问题。
先建立图像
创建阶段 挂载阶段 更新阶段 销毁阶段
│ │ │ │
setup() ──→ onBeforeMount ──→ onMounted ──→ onBeforeUpdate ──→ onUpdated ──→ onBeforeUnmount ──→ onUnmounted
(即将挂载) (已挂载) (即将更新) (已更新) (即将卸载) (已卸载)
跟着做
步骤 1:onMounted 挂载后执行
<script setup>
import { ref, onMounted } from 'vue'
const chartRef = ref(null)
onMounted(() => {
// 此时 DOM 已渲染,可以操作
console.log(chartRef.value) // <div> 元素
// 初始化图表、发请求、绑定事件
})
</script>
<template>
<div ref="chartRef">图表容器</div>
</template>
步骤 2:onUnmounted 销毁前清理
<script setup>
import { onMounted, onUnmounted } from 'vue'
let timer = null
onMounted(() => {
timer = setInterval(() => console.log('tick'), 1000)
})
onUnmounted(() => {
clearInterval(timer) // 必须清理,否则内存泄漏
})
</script>
步骤 3:onUpdated 更新后执行
<script setup>
import { ref, onUpdated } from 'vue'
const list = ref([])
onUpdated(() => {
// DOM 更新后执行,比如滚动到底部
const el = document.querySelector('.list')
el.scrollTop = el.scrollHeight
})
</script>
步骤 4:常用钩子速查
<script setup>
import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'vue'
onBeforeMount(() => console.log('即将挂载'))
onMounted(() => console.log('已挂载'))
onBeforeUpdate(() => console.log('即将更新'))
onUpdated(() => console.log('已更新'))
onBeforeUnmount(() => console.log('即将卸载'))
onUnmounted(() => console.log('已卸载'))
</script>
步骤 5:实际场景——请求数据 + 清理
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const data = ref(null)
let abortController = null
onMounted(async () => {
abortController = new AbortController()
try {
const res = await fetch('/api/data', { signal: abortController.signal })
data.value = await res.json()
} catch (e) {
if (e.name !== 'AbortError') throw e
}
})
onUnmounted(() => {
abortController?.abort() // 组件销毁时取消请求
})
</script>
讲清楚要点
- setup() 是最早的入口:组件创建时执行,此时还没有 DOM。
- onMounted 是最常用的钩子:DOM 已就绪,适合初始化第三方库、发请求。
- onUnmounted 必须清理副作用:定时器、事件监听、订阅、请求取消。
- onUpdated 要谨慎使用:频繁触发,避免在里面改数据导致死循环。
- 组合式 API 的钩子更灵活:可以写多个
onMounted,按功能组织。
你可能会懵的地方
-
Vue 2 的 created、mounted 去哪了? Vue 3 组合式 API 中,
setup()相当于beforeCreate+created,其他钩子加on前缀。 -
onMounted 和 onUpdated 都能操作 DOM,有什么区别? onMounted 只执行一次(首次挂载),onUpdated 每次数据更新后都执行。
-
为什么要在 onUnmounted 里清理定时器? 组件销毁后定时器还在跑,会操作已不存在的 DOM,导致内存泄漏和报错。
-
异步请求应该在哪个钩子里发? 通常
onMounted。如果数据在挂载前就要准备好,可以在setup()顶层用await(需配合<Suspense>)。 -
生命周期钩子能写多个吗? 能,Vue 会按注册顺序依次执行,适合逻辑拆分。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
| 在 setup() 里直接操作 DOM | DOM 还没渲染,拿到 null | 用 onMounted |
| 忘记在 onUnmounted 清理定时器 | 内存泄漏 | 成对出现:创建/清理 |
| 在 onUpdated 里修改数据 | 可能触发死循环 | 用 watch 或 computed |
| 用 created 发请求(选项式思维) | 组合式 API 没有 created | 在 setup() 或 onMounted 中发 |
| 在 onMounted 里写同步阻塞代码 | 页面白屏时间长 | 异步操作不阻塞渲染 |
卡点急救
- onMounted 里 ref 是 null:确认模板里写了
ref="xxx",且没有 v-if 条件未满足。 - 组件销毁后还在执行:检查是否有未清理的定时器/事件监听。
- onUpdated 频繁触发:检查是否监听了一个频繁变化的数据,考虑用 watch 替代。
面试常问
-
Vue 3 生命周期和 Vue 2 的区别? Vue 3 用
onXxx函数替代选项,更灵活;setup()替代beforeCreate/created。 -
哪个钩子可以拿到 DOM?
onMounted及之后。onBeforeMount时 DOM 还未渲染。 -
什么场景下用 onActivated / onDeactivated? 配合
<KeepAlive>缓存的组件,激活/失活时触发,常用于 Tab 切换保持状态。
自测三问
onMounted和setup()的执行顺序?- 为什么必须在
onUnmounted里清理定时器? onUpdated和watch在监听数据变化上有什么区别?
小结一句话
生命周期是组件的「人生阶段」,挂载后初始化,更新后同步,销毁前清理,掌握 onMounted / onUpdated / onUnmounted 就能处理 90% 的场景。
延伸
- Vue 官方文档 - 生命周期
- 下一课:事件处理——v-on、修饰符、自定义事件。