Vue3 生命周期钩子

生命周期流程图

开始

├─ 初始化阶段

│ │

│ ├─ setup() 🔵 Composition API入口

│ │

│ └─ beforeCreate() 🟡 Options API(组合式API中不存在)

│ │

│ └─ created() 🟡 Options API(组合式API中不存在)

├─ 挂载阶段

│ │

│ ├─ onBeforeMount() ⚪ 挂载前

│ │

│ ├─ 编译模板

│ │

│ ├─ 创建虚拟DOM

│ │

│ ├─ 挂载到真实DOM

│ │

│ └─ onMounted() ✅ 挂载完成

├─ 更新阶段

│ │

│ ├─ onBeforeUpdate() 🔄 更新前

│ │

│ ├─ 重新渲染虚拟DOM

│ │

│ ├─ 打补丁(DOM更新)

│ │

│ └─ onUpdated() ✅ 更新完成

├─ 卸载阶段

│ │

│ ├─ onBeforeUnmount() ⚠️ 卸载前

│ │

│ ├─ 移除DOM元素

│ │

│ └─ onUnmounted() ❌ 卸载完成

└─ 缓存组件特殊阶段(keep-alive)

├─ onActivated() 🔄 激活时

└─ onDeactivated() 💤 停用时

一、生命周期钩子对照表

Options API Composition API 调用时机 常用场景
beforeCreate ❌ 无对应 实例初始化后,数据观测/事件配置前 极少使用
created ❌ 无对应 实例创建完成,数据观测/事件配置完成 Options API 中用于数据初始化
beforeMount onBeforeMount 挂载开始之前 服务端渲染中获取数据
mounted onMounted 挂载完成后 DOM操作、数据请求、定时器、事件监听
beforeUpdate onBeforeUpdate 数据更新,DOM 重新渲染前 获取更新前的DOM状态
updated onUpdated 数据更新,DOM 重新渲染后 DOM依赖操作、第三方库初始化
beforeDestroy (Vue 2) onBeforeUnmount 实例销毁前 清理定时器、取消订阅、解绑事件
destroyed (Vue 2) onUnmounted 实例销毁后 极少使用
activated onActivated keep-alive 组件激活时 恢复数据、重新请求
deactivated onDeactivated keep-alive 组件停用时 暂停定时器、保存状态

二、组合式API用法详解

2.1 基本使用

javascript 复制代码
<script setup>
import { 
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onActivated,
  onDeactivated,
  ref 
} from 'vue'

const count = ref(0)

// 1. 挂载阶段
onBeforeMount(() => {
  console.log('1. onBeforeMount - 挂载前')
  // 此时组件尚未挂载到DOM
  console.log('DOM元素:', document.querySelector('.app')) // null
})

onMounted(() => {
  console.log('2. onMounted - 挂载完成')
  // ✅ 最佳实践:
  // - DOM操作(获取元素、初始化图表等)
  // - 发起数据请求
  // - 设置定时器
  // - 添加事件监听
  
  const el = document.querySelector('.app')
  console.log('DOM元素:', el) // 真实DOM
  
  // 示例:初始化图表
  // initChart()
  
  // 示例:请求数据
  // fetchData()
  
  // 示例:开始定时器
  // timer = setInterval(() => {}, 1000)
  
  // 示例:监听窗口大小变化
  // window.addEventListener('resize', handleResize)
})

// 2. 更新阶段
onBeforeUpdate(() => {
  console.log('3. onBeforeUpdate - 更新前')
  console.log('count更新前的值:', count.value)
  
  // 可以获取更新前的DOM状态
  const el = document.querySelector('.count')
  console.log('更新前文本:', el?.textContent)
})

onUpdated(() => {
  console.log('4. onUpdated - 更新完成')
  console.log('count更新后的值:', count.value)
  
  // ⚠️ 注意事项:
  // 1. 避免在updated中修改响应式数据,可能导致无限循环
  // 2. 确保DOM更新已经完成
  
  // ✅ 适用场景:
  // - 第三方库需要基于DOM初始化
  // - 获取更新后的DOM尺寸
  
  // 示例:重新初始化第三方库
  // if (chartInstance) {
  //   chartInstance.dispose()
  //   initChart()
  // }
})

// 3. 卸载阶段
onBeforeUnmount(() => {
  console.log('5. onBeforeUnmount - 卸载前')
  
  // ✅ 必须清理!防止内存泄漏
  // - 清除定时器
  // - 取消事件监听
  // - 清理全局状态
  // - 取消网络请求
  
  // 示例:清理定时器
  // if (timer) clearInterval(timer)
  
  // 示例:移除事件监听
  // window.removeEventListener('resize', handleResize)
  
  // 示例:取消未完成的请求
  // if (currentRequest) currentRequest.abort()
})

onUnmounted(() => {
  console.log('6. onUnmounted - 卸载完成')
  // 此时组件实例已完全销毁
  // 可用于记录日志或清理全局资源
})

// 4. keep-alive 相关
onActivated(() => {
  console.log('激活组件')
  // 组件从缓存中激活时调用
  // 恢复数据、重新开始定时器等
  
  // 示例:恢复定时器
  // if (timerPaused) {
  //   startTimer()
  //   timerPaused = false
  // }
})

onDeactivated(() => {
  console.log('停用组件')
  // 组件被缓存时调用
  // 暂停定时器、保存状态等
  
  // 示例:暂停定时器
  // pauseTimer()
  // timerPaused = true
})
</script>

<template>
  <div class="app">
    <div class="count">Count: {{ count }}</div>
    <button @click="count++">增加</button>
  </div>
</template>

2.2 执行顺序示例

javascript 复制代码
<!-- ParentComponent.vue -->
<script setup>
import ChildComponent from './ChildComponent.vue'
import { onMounted, ref } from 'vue'

const showChild = ref(true)

onMounted(() => {
  console.log('父组件 mounted')
})
</script>

<template>
  <div>
    <button @click="showChild = !showChild">切换子组件</button>
    <ChildComponent v-if="showChild" />
  </div>
</template>

<!-- ChildComponent.vue -->
<script setup>
import { onMounted, onUnmounted } from 'vue'

onMounted(() => {
  console.log('子组件 mounted')
})

onUnmounted(() => {
  console.log('子组件 unmounted')
})
</script>

<!-- 执行顺序:
1. 父组件 setup
2. 子组件 setup
3. 子组件 onMounted
4. 父组件 onMounted
5. 切换时:子组件 onUnmounted
-->

三、Options API 生命周期

javascript 复制代码
<script>
export default {
  data() {
    return {
      count: 0
    }
  },
  
  // 1. 初始化阶段(在 Composition API 中被 setup 替代)
  beforeCreate() {
    console.log('beforeCreate')
    // 此时:data未初始化,methods未定义
    // console.log(this.count) // undefined
  },
  
  created() {
    console.log('created')
    // ✅ 可以访问:data、methods、computed
    // ❌ 不能访问:DOM($el)
    // 用途:数据初始化、API请求(服务端渲染)
    
    console.log(this.count) // 0
    console.log(this.$el)   // undefined
  },
  
  // 2. 挂载阶段
  beforeMount() {
    console.log('beforeMount')
    // 模板编译完成,但尚未挂载到DOM
    console.log(this.$el) // undefined 或 编译前的模板
  },
  
  mounted() {
    console.log('mounted')
    // 与组合式API的onMounted用途相同
    this.$nextTick(() => {
      // 确保DOM已完全更新
    })
  },
  
  // 3. 更新阶段
  beforeUpdate() {
    console.log('beforeUpdate')
  },
  
  updated() {
    console.log('updated')
    // 小心:不要在这里修改数据,可能导致循环
  },
  
  // 4. 卸载阶段(Vue 2 命名)
  beforeDestroy() {  // Vue 3 中仍可用,但建议用 beforeUnmount
    console.log('beforeDestroy')
  },
  
  destroyed() {      // Vue 3 中仍可用,但建议用 unmounted
    console.log('destroyed')
  },
  
  // 5. keep-alive 相关
  activated() {
    console.log('activated')
  },
  
  deactivated() {
    console.log('deactivated')
  },
  
  // 6. 错误处理(Vue 2.5+)
  errorCaptured(err, instance, info) {
    console.error('错误捕获:', err)
    // 可以返回 false 阻止错误继续向上传播
    return false
  }
}
</script>

四、生命周期使用统计

根据实际项目经验,各生命周期使用频率:

  1. 高频使用 (80% 场景)

    • onMounted - DOM操作、数据请求、事件监听

    • onUnmounted - 清理工作

  2. 中频使用 (15% 场景)

    • onUpdated - 第三方库集成

    • onBeforeUnmount - 确保清理

  3. 低频使用 (5% 场景)

    • onBeforeMount - 服务端渲染特殊需求

    • onBeforeUpdate - 特定优化场景

    • onActivated/onDeactivated - 使用 keep-alive 时

相关推荐
We་ct8 分钟前
LeetCode 35. 搜索插入位置:二分查找的经典应用
前端·算法·leetcode·typescript·个人开发
左耳咚9 分钟前
Claude Code 中的 SubAgent
前端·ai编程·claude
FPGA小迷弟11 分钟前
高频时钟设计:FPGA 多时钟域同步与时序收敛实战方案
前端·学习·fpga开发·verilog·fpga
IT古董11 分钟前
【前端】企业级前端调试体系设计(含日志埋点 + Eruda 动态注入 + Sentry)
前端·sentry
gis开发15 分钟前
cesium 中添加鹰眼效果
前端·javascript
前端付豪24 分钟前
Memory V1:让 AI 记住你的关键信息
前端·后端·llm
毛骗导演33 分钟前
@tencent-weixin/openclaw-weixin 插件深度解析(三):CDN 媒体服务深度解析
前端·架构
谁在黄金彼岸35 分钟前
Threejs实现 3D 看房效果
前端
谁在黄金彼岸38 分钟前
Threejs实现物理运动模拟
前端
bluceli39 分钟前
JavaScript动态导入与代码分割:优化应用加载性能的终极方案
javascript