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 时

相关推荐
程序员Sunday10 小时前
JavaScript 事件循环面试题,宏任务与微任务怎么执行|Sunday面试指南
开发语言·javascript·面试·校招·事件循环·程序员sunday
Setsuna_F_Seiei10 小时前
前端转型 Agent 开发 06 之 Agent Memory 记忆系统(让 Agent 更智能,更懂你)
前端·agent·ai编程
志尊宝10 小时前
Vue3 零基础每日笔记(073):keep-alive 页面缓存实战——列表页返回不丢状态
vue.js·笔记·缓存·#vue #前端 #前端开发·#javascript·#vue.js
zhangzeyuaaa11 小时前
Ruby 多线程、GVL(GIL)与 Mutex 完全指南
开发语言·前端·ruby
默_笙11 小时前
🌊 向量库和 ES 都查不出"关系",我只好给奶茶建了一张人脉网
前端·javascript
优选资讯11 小时前
标签打印软件怎么对接 Excel 数据
前端·excel
思无邪6612 小时前
用 AI 做 JS 逆向:从抓包到复现的完整方法论
开发语言·javascript·人工智能
一个风轻云淡12 小时前
GCC 和 GDB命令简单解读
java·linux·前端
u01110267513 小时前
图片处理接口如何统一错误信息 前端提示与后端错误码设计
前端·状态模式
福兮说13 小时前
浏览器里把 iPhone 的 HEIC 转成 JPG:Chrome 解不开、转完大了七成、拍摄时间全丢,六个坑实测
前端·javascript·图像处理·chrome·ios·iphone·heic