Appearance
✨ 生命周期 👌
本章目标
- 理解组件从创建到销毁的关键时间点与钩子作用
- 熟悉常用钩子:
onMounted、onUpdated、onUnmounted等 - 正确在钩子中进行 DOM 访问、事件清理与数据请求
- 避免与 Vue2 选项式钩子的混用造成时机混乱
什么是生命周期
组件从创建到最终销毁,会依次经历若干阶段(如挂载、更新、卸载),框架在这些阶段暴露“钩子函数”供开发者在合适时机执行业务逻辑。
完整的生命周期图如下:

使用时机要点
- 只有在
onMounted触发后才能安全访问真实 DOM(如el.value) - 在
onUnmounted中做清理(移除事件监听、取消定时器、断开订阅) - 只在需要的阶段做工作:避免在
onUpdated中执行昂贵计算导致卡顿
快速入门:onMounted
onMounted 在组件初次完成渲染并插入 DOM 后触发,常用于发起数据请求或读取 DOM。
vue
<template>
<div>
<h1>用户列表</h1>
<ul v-if="!loading">
<li v-for="user in users" :key="user.id">
{{ user.name }} - {{ user.email }}
</li>
</ul>
<div v-else>加载中...</div>
<div v-if="error">出错啦:{{ error }}</div>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
const users = ref([]);
const loading = ref(false);
const error = ref(null);
onMounted(async () => {
loading.value = true;
try {
const res = await fetch("https://jsonplaceholder.typicode.com/users");
if (!res.ok) throw new Error("请求失败");
users.value = await res.json();
} catch (err) {
error.value = err.message;
} finally {
loading.value = false;
}
});
</script>在挂载后访问 DOM
vue
<template>
<h2 ref="title">Hello</h2>
</template>
<script setup>
import { ref, onMounted } from "vue";
const title = ref(null);
onMounted(() => {
// 此处才能安全访问真实 DOM
console.log("标题宽度:", title.value.offsetWidth);
});
</script>常用钩子一览
onBeforeMount:组件挂载前(尚未渲染 DOM)onMounted:组件挂载后(可以访问 DOM)onBeforeUpdate:响应式更新前(虚拟 DOM 已生成、未打补丁)onUpdated:更新完成后(DOM 已与状态同步)onBeforeUnmount:卸载前(即将移除组件)onUnmounted:卸载后(做资源清理)onActivated/onDeactivated:配合KeepAlive缓存组件时的激活/失活onErrorCaptured:捕获子组件渲染/事件中的错误
示例:在卸载时清理副作用
vue
<script setup>
import { onMounted, onUnmounted } from "vue";
const handler = () => console.log("scrolling");
onMounted(() => {
window.addEventListener("scroll", handler);
});
onUnmounted(() => {
window.removeEventListener("scroll", handler);
});
</script>示例:更新后读取最新布局
vue
<script setup>
import { ref, onUpdated } from "vue";
const count = ref(0);
onUpdated(() => {
// 组件已更新到最新状态,可进行依赖最新 DOM 的逻辑
console.log("组件已更新到最新 count:", count.value);
});
</script>示例:KeepAlive 的激活与失活
vue
<script setup>
import { onActivated, onDeactivated } from "vue";
onActivated(() => {
console.log("组件被激活(再次展示)");
});
onDeactivated(() => {
console.log("组件被失活(被缓存不再展示)");
});
</script>示例:捕获错误
vue
<script setup>
import { onErrorCaptured } from "vue";
onErrorCaptured((err, instance, info) => {
console.error("捕获错误:", err, info);
// 返回 false 可阻止错误继续向上传播
return false;
});
</script>常见误区
- 在
setup之外或异步回调中直接使用生命周期钩子,可能导致未注册或执行时机异常 - 在
onUpdated中做重计算或频繁 DOM 操作,会造成性能问题;必要时做节流/防抖 - SSR 场景下没有真实 DOM,需在客户端挂载后再做 DOM 相关逻辑
与 Vue2 生命周期的关系
Vue3 仍兼容 Vue2 的选项式生命周期(如 mounted、updated 等)。但在同一组件内混用两套钩子会增加复杂度与时机差异。
vue
<template>
<div>Vue2 与 Vue3 钩子并存示例(不推荐混用)</div>
<p>打开控制台查看执行顺序</p>
<button @click="msg = msg + '!'">更新</button>
<p>{{ msg }}</p>
</template>
<script>
import { onMounted, onUpdated } from "vue";
export default {
data() {
return { msg: "Hello" };
},
mounted() {
console.log("Vue2 mounted");
},
updated() {
console.log("Vue2 updated");
},
setup() {
onMounted(() => {
console.log("Vue3 onMounted");
});
onUpdated(() => {
console.log("Vue3 onUpdated");
});
},
};
</script>建议
- 在同一组件内优先统一为“组合式 API”的生命周期钩子,便于维护与类型推断
- 若使用选项式风格,可保持整组件都采用选项式,避免混合写法
小结
- 生命周期钩子提供了在关键阶段执行逻辑的能力
onMounted做首屏数据与 DOM 访问;onUnmounted做清理;onUpdated做变更后处理- 合理选择钩子并控制副作用范围,有助于可维护与高性能的组件实现
