跳到主要内容

Vue 2 / Vue 3 生命周期

生命周期这题,面试官通常不是想听你背钩子名,而是想确认你是否真的理解:

  • 组件在什么阶段初始化数据、建立响应式、生成 DOM、更新 DOM、销毁副作用
  • Vue 2 和 Vue 3 在“写法”和“时机表达”上到底差在哪
  • 哪些业务应该放在哪个阶段做,为什么

本文默认对比 Vue 2.x Options APIVue 3.x Composition API / Options API

面试速答(30 秒版 TL;DR)

  • 生命周期本质上就是组件从 创建 -> 挂载 -> 更新 -> 卸载 -> 缓存激活/失活 的一套时机点。
  • Vue 2 常背的一条线是:beforeCreate -> created -> beforeMount -> mounted -> beforeUpdate -> updated -> beforeDestroy -> destroyed
  • Vue 3 仍然有 Options API 生命周期,但在实际项目里更常用的是组合式 API:setuponMountedonUpdatedonUnmounted 等。
  • Vue 3 里最重要的变化不是“钩子改名”本身,而是:
    • 组合式 API 让同一阶段的逻辑可以按功能聚合
    • 卸载钩子从 beforeDestroy/destroyed 改成 beforeUnmount/unmounted
    • setup() 成了创建阶段的主要入口,很多初始化逻辑不再写进 created
  • keep-alive 是加分点:它不是销毁重建,而是 activated/deactivated

一、先建立心智模型:生命周期解决的是什么问题

组件不是“函数一跑就完了”,它有一个完整的存在周期:

  1. 框架先创建组件实例
  2. 初始化 propsdatacomputedwatch、响应式依赖
  3. 执行渲染函数,得到 VNode
  4. 把 VNode patch 成真实 DOM
  5. 数据变化后重新渲染、比对、更新 DOM
  6. 组件离开页面时销毁实例、事件、定时器、订阅

所以生命周期的本质,是给业务代码提供“插入点”。

二、Vue 2 生命周期主线

1. 创建阶段

  • beforeCreate:实例刚创建,datapropsmethods 还没完成代理。
  • created:响应式、方法、监听等已初始化完成,但还没有真实 DOM。

这个阶段适合做:

  • 初始化普通数据
  • 发起不依赖 DOM 的请求
  • 注册事件总线、订阅等

这个阶段不适合做:

  • 操作真实 DOM
  • 读取组件渲染后的尺寸位置

2. 挂载阶段

  • beforeMount:首次渲染前
  • mounted:组件已经挂到页面,真实 DOM 可用

适合放在 mounted 的逻辑:

  • DOM 测量
  • 第三方 DOM 库初始化
  • 依赖 ref 的操作

3. 更新阶段

  • beforeUpdate:响应式数据变了,但 DOM 还没更新
  • updated:DOM 已完成本轮更新

面试里要强调:

  • Vue 的更新不是同步立即改 DOM,而是调度后批量刷新
  • 如果你要拿“更新后的 DOM”,一般看 updatednextTick

4. 卸载阶段

  • beforeDestroy
  • destroyed

这个阶段要清理:

  • setTimeout / setInterval
  • 手动绑定的 DOM 事件
  • WebSocket、订阅、观察器

5. 缓存组件阶段

keep-alive 包住的组件,不会频繁销毁重建,而是:

  • 首次进入:照常创建、挂载
  • 切走时:触发 deactivated
  • 切回时:触发 activated

这也是为什么标签页缓存、列表返回保留滚动位置,经常配合 keep-alive

三、Vue 3 生命周期怎么理解

1. Options API 仍然存在,但命名更统一

Vue 3 不是把生命周期推翻重来,而是做了统一:

Vue 2Vue 3
beforeDestroybeforeUnmount
destroyedunmounted
activatedactivated
deactivateddeactivated

其余创建、挂载、更新阶段的含义基本一致。

2. 组合式 API 下,setup() 是创建阶段入口

Vue 3 真正的变化点,是大量逻辑不再分散在 datamethodswatchcreated 里,而是放进 setup()

可以把它理解成:

  • 组件初始化早期执行 setup()
  • 在这里声明响应式状态、计算属性、监听、副作用
  • 再配合 onMountedonUpdatedonUnmounted 等注册各阶段逻辑

最重要的答题点:

  • setup() 里没有组件实例 this
  • setup() 更像“组件逻辑装配阶段”
  • 原来放在 beforeCreate/created 的很多逻辑,在 Vue 3 里会自然转移到 setup()

3. Vue 3 常用生命周期 API

import { onMounted, onUpdated, onUnmounted, onActivated, onDeactivated } from 'vue'

最常考的对应关系:

场景Vue 2Vue 3 常用写法
挂载后操作 DOMmountedonMounted
更新后拿新 DOMupdatedonUpdatednextTick
卸载前清理副作用beforeDestroy/destroyedonUnmounted
keep-alive 激活/失活activated/deactivatedonActivated/onDeactivated

四、Vue 2 和 Vue 3 的关键差异,不要只答“名字变了”

1. 差异一:逻辑组织方式变了

Vue 2 的问题是:同一块业务逻辑会分散在多个选项里。

例如一个“用户列表”功能,可能拆在:

  • data
  • computed
  • watch
  • mounted
  • methods

Vue 3 则可以按“功能”聚合:

import { ref, onMounted, watch } from 'vue'

export function useUserList() {
const list = ref([])
const keyword = ref('')

onMounted(loadUsers)
watch(keyword, loadUsers)

async function loadUsers() {
// ...
}

return { list, keyword, loadUsers }
}

这就是 Vue 3 生命周期变化背后的真正收益:时机仍然存在,但逻辑组织方式更合理。

2. 差异二:销毁语义更准确

Vue 2 的 destroy 容易让人误以为是“彻底物理销毁 DOM”。

Vue 3 改成 unmount,更贴近渲染器语义:组件从当前渲染树卸载

3. 差异三:组合式 API 的注册必须同步完成

这是高频追问。

onMountedonUnmounted 这类组合式生命周期注册,通常都要求在 setup() 的同步阶段完成。不要在异步回调里再临时注册,否则时机可能丢失。

五、典型业务到底该放哪

1. 请求数据放哪

面试里更稳的答法是:

  • 不依赖 DOM 的初始化请求:
    • Vue 2 可放 created
    • Vue 3 常放 setup() 中触发,或 onMounted
  • 如果请求结果会影响首屏渲染,但不需要 DOM,优先尽早发起
  • 如果请求依赖 DOM 容器尺寸、第三方实例,就放 mounted/onMounted

2. DOM 操作放哪

  • Vue 2:mountedupdated
  • Vue 3:onMountedonUpdatednextTick

3. 清理逻辑放哪

  • Vue 2:beforeDestroy/destroyed
  • Vue 3:onUnmounted

一个最小例子:

import { onMounted, onUnmounted } from 'vue'

let timer: ReturnType<typeof setInterval> | null = null

onMounted(() => {
timer = setInterval(() => {
console.log('polling')
}, 1000)
})

onUnmounted(() => {
if (timer) clearInterval(timer)
})

六、生命周期执行顺序怎么背

Vue 2 常规组件

beforeCreate -> created -> beforeMount -> mounted -> beforeUpdate -> updated -> beforeDestroy -> destroyed

Vue 3 组合式 API 口径

可以记成:

setup -> onBeforeMount -> onMounted -> onBeforeUpdate -> onUpdated -> onBeforeUnmount -> onUnmounted

如果用了缓存组件,再补上:

onActivated / onDeactivated

七、典型题 & 标准答法

Q1:createdmounted 区别是什么?

created 时组件实例和响应式数据已经就绪,但真实 DOM 还没挂载;mounted 时 DOM 已经生成,可以拿 ref、做尺寸计算、初始化图表或第三方库。是否依赖 DOM,是二者最核心的分界线。

Q2:Vue 3 里还有没有 created

:有,Vue 3 的 Options API 仍支持这些钩子。但在实际 Vue 3 项目里,更常把初始化逻辑放进 setup(),再配合 onMounted 等组合式生命周期,因此面试更常考的是 setup 这一套。

Q3:为什么 keep-alive 不走销毁重建?

:因为它的目标就是缓存组件实例和状态,避免频繁重新创建。切走时不是 unmount,而是失活 deactivated;切回时是激活 activated

八、常见误区

  • 误区 1:把生命周期理解成“固定背诵题”。 真正重要的是“这个阶段能不能拿到 DOM、能不能拿到实例、适不适合清理副作用”。
  • 误区 2:所有请求都必须放 mounted。 不依赖 DOM 的请求没必要等到挂载后再发。
  • 误区 3:updated 里无脑继续改响应式数据。 这容易造成重复更新,甚至死循环。
  • 误区 4:忘记清理副作用。 生命周期不只是“开始做事”,更重要的是“结束时收口”。

速记要点

  • 生命周期本质:组件各阶段的业务插入点
  • Vue 2 主线:创建、挂载、更新、销毁、缓存激活
  • Vue 3 重点:setup() + onXxx
  • DOM 操作看 mounted/onMounted
  • 清理副作用看 beforeDestroy/destroyedonUnmounted
  • keep-alive 记住 activated/deactivated