在选项式 API 中,我们通过在组件选项对象中定义 created、mounted 等方法来声明生命周期逻辑。切换到组合式 API 后,这些生命周期方法变为一系列以 on 开头的函数,在 setup(或 <script setup>)中调用即可。
映射关系速查表
| 选项式 API 钩子 | 组合式 API 钩子函数 | 执行时机简介 |
|------------------|------------------------|--------------|
| beforeCreate | 无直接对应 | 使用 setup() 本身就替代了它,在组件实例初始化之前执行 |
| created | 无直接对应 | 使用 setup() 替代,在实例创建完成后、模板编译前执行 |
| beforeMount | onBeforeMount | 组件即将被挂载到 DOM 前调用 |
| mounted | onMounted | 组件挂载完成后调用,可访问真实 DOM 节点 |
| beforeUpdate | onBeforeUpdate | 响应式数据改变,DOM 更新前调用 |
| updated | onUpdated | DOM 更新完成后调用,注意避免在此无限更新 |
| beforeUnmount | onBeforeUnmount | 组件即将销毁前调用,用于清理定时器、取消订阅等 |
| unmounted | onUnmounted | 组件已销毁后调用 |
| errorCaptured | onErrorCaptured | 捕获后代组件的错误 |
| activated | onActivated | <keep-alive> 缓存的组件激活时调用 |
| deactivated | onDeactivated | <keep-alive> 缓存的组件失活时调用 |
| serverPrefetch | onServerPrefetch | SSR 期间,组件渲染前异步获取数据 |
为什么没有 onBeforeCreate 和 onCreated?
因为 setup 函数本身就是围绕 beforeCreate 和 created 阶段设计的。你在 setup 中写的任何代码,实际上就在这两个阶段之间执行。因此不需要额外的钩子。
使用示例
<script setup>
import { onMounted, onUnmounted, ref } from 'vue'
const el = ref(null)
onMounted(() => {
// 此时可安全访问 DOM
console.log(el.value) // <div>
})
onUnmounted(() => {
// 清理工作,如移除事件监听
console.log('组件已卸载,清理完成')
})
</script>
<template>
<div ref="el">Hello Lifecycle</div>
</template>
注意事项
- 调用顺序:多个
onMounted钩子的执行顺序与它们的注册顺序一致,且都在同一个组件挂载阶段执行。 - 只能在
setup同步调用:这些钩子函数必须在setup或<script setup>顶层同步注册,不能放在条件语句或异步回调中,否则它们会失去与当前组件实例的绑定。 onUpdated的坑:如果在其回调中修改响应式数据,可能导致无限循环,一般使用watch代替。onBeforeUnmount/onUnmounted的重要性:手动添加的全局事件监听、定时器、动画帧等,务必在这两个阶段清理,防止内存泄漏。
组合式生命周期的最大好处是:相同的逻辑(如数据获取+清理)可以封装进一个自定义 Hook,一次编写多处复用,让代码组织更加聚合。