Skip to content

Vue3 生命周期完全指南

一、生命周期概述

Vue3 的生命周期是指 Vue 实例从创建到销毁的整个过程,在这个过程中会自动触发一系列的钩子函数,开发者可以在这些钩子函数中执行特定的业务逻辑。

二、Vue3 生命周期钩子

2.1 创建阶段

beforeCreate

执行时机:实例初始化之后,数据观测 (data observer) 和事件配置之前调用。

作用功能

  • 组件实例刚被创建,组件属性计算之前
  • 此时 datamethodscomputed 等都还未初始化
  • 无法访问 this.datathis.methods

使用场景

  • 极少使用,一般用于插件开发中的初始化工作
  • 可以添加一些自定义的初始化逻辑

代码示例

javascript
import { onBeforeMount } from 'vue'

setup() {
  onBeforeMount(() => {
    console.log('组件即将挂载')
  })
}

created

执行时机:实例创建完成后调用,此时实例已完成数据观测、属性和方法的运算,但 DOM 还未挂载。

作用功能

  • datamethodscomputedwatch 都已初始化完成
  • 可以访问组件的数据和方法
  • 无法访问 DOM 元素($el 尚不存在)

使用场景

  • 调用异步请求获取初始数据
  • 初始化组件状态
  • 订阅事件或设置定时器
  • 访问和操作组件数据

代码示例

javascript
export default {
  data() {
    return {
      userList: []
    }
  },
  created() {
    this.fetchUserList()
  },
  methods: {
    async fetchUserList() {
      this.userList = await api.getUsers()
    }
  }
}

2.2 挂载阶段

beforeMount

执行时机:在挂载开始之前被调用,相关的 render 函数首次被调用。

作用功能

  • 模板编译完成,但还未渲染到页面
  • this.$el 已存在但尚未挂载到 DOM
  • 此时 DOM 还是虚拟 DOM

使用场景

  • 在渲染前最后一次修改数据的机会
  • 不会触发重新渲染的过程

代码示例

javascript
export default {
  data() {
    return {
      message: 'Hello'
    }
  },
  beforeMount() {
    this.message = 'Hello Vue3'
    console.log('DOM 即将更新')
  }
}

mounted

执行时机:实例挂载到 DOM 后调用,此时可以访问 DOM 元素。

作用功能

  • 组件 DOM 已渲染完成
  • 可以访问 this.$el
  • 子组件可能还未完成挂载(使用 this.$nextTick 确保所有子组件挂载完成)

使用场景

  • 操作 DOM 元素
  • 初始化第三方库(如 ECharts、Swiper 等)
  • 绑定事件监听器
  • 执行需要 DOM 存在的操作

代码示例

javascript
export default {
  mounted() {
    this.initChart()

    this.$nextTick(() => {
      console.log('所有子组件已挂载完成')
    })
  },
  methods: {
    initChart() {
      const chart = echarts.init(this.$refs.chartDom)
      chart.setOption(this.chartOptions)
    }
  }
}

2.3 更新阶段

beforeUpdate

执行时机:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。

作用功能

  • 数据已更新,但 DOM 还未更新
  • 可以在此进一步更改状态,不会触发附加的重渲染过程

使用场景

  • 获取更新前 DOM 的状态
  • 在更新前保存某些数据(如滚动位置)

代码示例

javascript
export default {
  data() {
    return {
      items: []
    }
  },
  beforeUpdate() {
    this.savedScrollTop = window.scrollY
  }
}

updated

执行时机:由于数据更改导致的虚拟 DOM 重新渲染和打补丁之后调用。

作用功能

  • 组件 DOM 已更新完成
  • 可以执行依赖于 DOM 更新后的操作
  • 避免在此期间更改状态,可能导致无限循环

使用场景

  • DOM 更新后执行操作
  • 重新计算布局或尺寸
  • 注意:避免在此钩子中更改响应式数据

代码示例

javascript
export default {
  updated() {
    this.$nextTick(() => {
      const height = this.$refs.container.offsetHeight
      console.log('容器高度:', height)
    })
  }
}

2.4 销毁阶段

beforeUnmount (Vue3 新增)

执行时机:在卸载组件实例之前调用。

作用功能

  • 组件实例仍然完全可用
  • 可以访问 thisdatamethods
  • DOM 元素仍然存在

使用场景

  • 清除定时器
  • 取消事件监听
  • 取消网络请求
  • 清除第三方实例

代码示例

javascript
export default {
  data() {
    return {
      timer: null
    }
  },
  mounted() {
    this.timer = setInterval(() => {
      console.log('定时执行')
    }, 1000)
  },
  beforeUnmount() {
    clearInterval(this.timer)
    window.removeEventListener('resize', this.handleResize)
  }
}

unmounted (Vue3 新增)

执行时机:卸载组件实例后调用。

作用功能

  • 组件的所有子组件都已卸载
  • 所有的响应式效果都已停止
  • DOM 元素已被移除

使用场景

  • 最终清理工作
  • 释放内存
  • 记录日志

代码示例

javascript
export default {
  unmounted() {
    console.log('组件已完全卸载')
  }
}

2.5 特殊生命周期钩子

activated

执行时机:被 keep-alive 缓存的组件激活时调用。

作用功能

  • 组件从缓存中被激活时触发
  • 可以获取到组件的最新状态

使用场景

  • 刷新缓存数据
  • 重新发起网络请求
  • 恢复滚动位置
  • 重新启动定时器

代码示例

javascript
export default {
  activated() {
    this.fetchLatestData()
    this.restoreScrollPosition()
  }
}

deactivated

执行时机:被 keep-alive 缓存的组件停用时调用。

作用功能

  • 组件被缓存时触发
  • 组件实例会被保留在内存中

使用场景

  • 暂停不必要的操作(如定时器)
  • 保存组件状态
  • 清除临时数据

代码示例

javascript
export default {
  deactivated() {
    this.pauseVideo()
    this.saveCurrentState()
  }
}

errorCaptured

执行时机:当捕获一个来自子孙组件的错误时被调用。

作用功能

  • 捕获子组件传递上来的错误
  • 可以阻止错误继续向上传播

参数

  • err:错误对象
  • vm:发生错误的组件实例
  • info:Vue 特定的错误信息

使用场景

  • 全局错误处理
  • 错误日志上报
  • 错误边界处理

代码示例

javascript
export default {
  errorCaptured(err, vm, info) {
    console.error('捕获到错误:', err)
    console.error('错误来源:', vm)
    console.error('错误信息:', info)

    // 上报错误到服务器
    this.reportError(err, vm, info)

    // 返回 false 阻止错误继续向上传播
    return false
  }
}

renderTracked (Vue3 新增)

执行时机:跟踪虚拟 DOM 重新渲染时调用。

作用功能

  • 开发模式下调试使用
  • 告知哪个操作触发了重新渲染

使用场景

  • 性能优化调试
  • 追踪响应式依赖

代码示例

javascript
export default {
  renderTracked(e) {
    console.log('渲染被追踪:', e)
  }
}

renderTriggered (Vue3 新增)

执行时机:虚拟 DOM 重新渲染被触发时调用。

作用功能

  • 开发模式下调试使用
  • 告知是什么触发了重新渲染

使用场景

  • 性能优化调试
  • 分析渲染触发原因

代码示例

javascript
export default {
  renderTriggered(e) {
    console.log('渲染被触发:', e)
  }
}

serverPrefetch (SSR)

执行时机:服务器端渲染期间调用。

作用功能

  • 在服务器端渲染时预取数据
  • 返回 Promise 以延迟渲染

使用场景

  • SSR 应用中预取异步数据
  • 服务端数据初始化

代码示例

javascript
export default {
  data() {
    return {
      article: null
    }
  },
  serverPrefetch() {
    return fetchArticle(this.id).then(article => {
      this.article = article
    })
  }
}

三、Composition API 生命周期钩子

Vue3 的 Composition API 提供了与 Options API 对应的生命周期钩子函数:

3.1 钩子函数对照表

Options APIComposition API
beforeCreatesetup()
createdsetup()
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted
activatedonActivated
deactivatedonDeactivated
errorCapturedonErrorCaptured
renderTrackedonRenderTracked
renderTriggeredonRenderTriggered

3.2 Composition API 使用示例

javascript
import {
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onActivated,
  onDeactivated,
  onErrorCaptured,
  ref,
  onScopeDispose
} from 'vue'

export default {
  setup() {
    const count = ref(0)

    // beforeCreate 和 created 被 setup 替代
    console.log('setup 执行,相当于 beforeCreate 和 created')

    onBeforeMount(() => {
      console.log('组件即将挂载')
    })

    onMounted(() => {
      console.log('组件已挂载')
      // 可以在这里操作 DOM
    })

    onBeforeUpdate(() => {
      console.log('数据即将更新')
    })

    onUpdated(() => {
      console.log('数据已更新')
    })

    onBeforeUnmount(() => {
      console.log('组件即将卸载')
    })

    onUnmounted(() => {
      console.log('组件已卸载')
    })

    onActivated(() => {
      console.log('组件被激活')
    })

    onDeactivated(() => {
      console.log('组件被停用')
    })

    onErrorCaptured((err, instance, info) => {
      console.error('捕获错误:', err)
      return false
    })

    // 新增:作用域销毁时调用
    onScopeDispose(() => {
      console.log('作用域销毁')
    })

    return {
      count
    }
  }
}

3.3 自定义组合式函数中的生命周期

javascript
import { onMounted, onUnmounted, ref } from 'vue'

// 自定义组合式函数
function useMousePosition() {
  const x = ref(0)
  const y = ref(0)

  function update(e) {
    x.value = e.pageX
    y.value = e.pageY
  }

  onMounted(() => {
    window.addEventListener('mousemove', update)
  })

  onUnmounted(() => {
    window.removeEventListener('mousemove', update)
  })

  return { x, y }
}

// 在组件中使用
export default {
  setup() {
    const { x, y } = useMousePosition()
    return { x, y }
  }
}

四、Vue3 与 Vue2 生命周期差异对比

4.1 钩子名称变更

Vue2Vue3说明
beforeCreatesetup()Vue3 中被 setup 替代
createdsetup()Vue3 中被 setup 替代
beforeMountonBeforeMount名称不变,需在 setup 中使用 onXxx
mountedonMounted名称不变
beforeUpdateonBeforeUpdate名称不变
updatedonUpdated名称不变
beforeDestroyonBeforeUnmount⚠️ 重命名
destroyedonUnmounted⚠️ 重命名
activatedonActivated名称不变
deactivatedonDeactivated名称不变
errorCapturedonErrorCaptured名称不变
-onRenderTracked✨ Vue3 新增
-onRenderTriggered✨ Vue3 新增

4.2 主要差异详解

差异一:beforeCreate 和 created 被移除

Vue2 写法

javascript
export default {
  beforeCreate() {
    console.log('实例初始化')
  },
  created() {
    console.log('实例创建完成')
    this.fetchData()
  }
}

Vue3 写法

javascript
export default {
  setup() {
    // setup 本身就相当于 beforeCreate 和 created
    console.log('setup 执行')

    // 直接在 setup 中调用方法
    fetchData()

    return {}
  }
}

原因:Composition API 的 setup 在组件创建之前执行,因此不再需要这两个钩子。


差异二:销毁钩子重命名

Vue2

javascript
export default {
  beforeDestroy() {
    console.log('即将销毁')
  },
  destroyed() {
    console.log('已销毁')
  }
}

Vue3

javascript
export default {
  beforeUnmount() {
    console.log('即将卸载')
  },
  unmounted() {
    console.log('已卸载')
  }
}

// 或 Composition API
import { onBeforeUnmount, onUnmounted } from 'vue'

setup() {
  onBeforeUnmount(() => {
    console.log('即将卸载')
  })

  onUnmounted(() => {
    console.log('已卸载')
  })
}

原因:更准确地描述组件从 DOM 中卸载的过程,而不是"销毁"。


差异三:新增调试钩子

Vue3 新增

javascript
import { onRenderTracked, onRenderTriggered } from 'vue'

export default {
  setup() {
    onRenderTracked(e => {
      console.log('渲染被追踪:', e)
      // e.key - 追踪的响应式属性
      // e.target - 目标对象
      // e.type - 追踪类型
    })

    onRenderTriggered(e => {
      console.log('渲染被触发:', e)
      // e.key - 触发的响应式属性
      // e.target - 目标对象
      // e.type - 触发类型
      // e.newValue - 新值
      // e.oldValue - 旧值
    })
  }
}

用途:用于开发调试,帮助开发者了解组件渲染的触发原因。


4.3 完整对比示例

Vue2 Options API

javascript
export default {
  data() {
    return {
      message: 'Hello Vue2'
    }
  },
  beforeCreate() {
    console.log('beforeCreate')
  },
  created() {
    console.log('created')
    this.initData()
  },
  beforeMount() {
    console.log('beforeMount')
  },
  mounted() {
    console.log('mounted')
    this.initChart()
  },
  beforeUpdate() {
    console.log('beforeUpdate')
  },
  updated() {
    console.log('updated')
  },
  beforeDestroy() {
    console.log('beforeDestroy')
    this.cleanup()
  },
  destroyed() {
    console.log('destroyed')
  },
  methods: {
    initData() {},
    initChart() {},
    cleanup() {}
  }
}

Vue3 Composition API

javascript
import {
  ref,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted
} from 'vue'

export default {
  setup() {
    const message = ref('Hello Vue3')

    // beforeCreate 和 created 被 setup 替代
    console.log('setup (beforeCreate + created)')
    initData()

    onBeforeMount(() => {
      console.log('onBeforeMount')
    })

    onMounted(() => {
      console.log('onMounted')
      initChart()
    })

    onBeforeUpdate(() => {
      console.log('onBeforeUpdate')
    })

    onUpdated(() => {
      console.log('onUpdated')
    })

    onBeforeUnmount(() => {
      console.log('onBeforeUnmount')
      cleanup()
    })

    onUnmounted(() => {
      console.log('onUnmounted')
    })

    function initData() {}
    function initChart() {}
    function cleanup() {}

    return {
      message
    }
  }
}

五、生命周期执行顺序

5.1 组件挂载流程

父组件 setup

父组件 onBeforeMount

子组件 setup

子组件 onBeforeMount

子组件 onMounted

父组件 onMounted

5.2 组件更新流程

父组件 onBeforeUpdate

子组件 onBeforeUpdate

子组件 onUpdated

父组件 onUpdated

5.3 组件卸载流程

父组件 onBeforeUnmount

子组件 onBeforeUnmount

子组件 onUnmounted

父组件 onUnmounted

5.4 完整执行顺序示例

javascript
// Parent.vue
import { onMounted, onBeforeMount } from 'vue'

export default {
  setup() {
    console.log('1. Parent setup')

    onBeforeMount(() => {
      console.log('2. Parent onBeforeMount')
    })

    onMounted(() => {
      console.log('5. Parent onMounted')
    })
  }
}

// Child.vue
import { onMounted, onBeforeMount } from 'vue'

export default {
  setup() {
    console.log('3. Child setup')

    onBeforeMount(() => {
      console.log('4. Child onBeforeMount')
    })

    onMounted(() => {
      console.log('6. Child onMounted')
    })
  }
}

六、最佳实践

6.1 数据请求时机

javascript
// ✅ 推荐:在 created/setup 中请求
export default {
  setup() {
    const data = ref(null)

    // setup 执行时立即请求,更早获取数据
    fetchData().then(res => {
      data.value = res
    })

    return { data }
  }
}

// ✅ 需要 DOM 时在 mounted 中请求
export default {
  setup() {
    const chartRef = ref(null)

    onMounted(async () => {
      const data = await fetchData()
      initChart(chartRef.value, data)
    })

    return { chartRef }
  }
}

6.2 清理资源

javascript
// ✅ 正确清理资源
export default {
  setup() {
    let timer = null

    onMounted(() => {
      timer = setInterval(() => {
        console.log('定时任务')
      }, 1000)

      window.addEventListener('resize', handleResize)
    })

    onUnmounted(() => {
      // 清理定时器
      if (timer) {
        clearInterval(timer)
        timer = null
      }

      // 移除事件监听
      window.removeEventListener('resize', handleResize)
    })

    function handleResize() {}

    return {}
  }
}

6.3 使用组合式函数封装生命周期逻辑

javascript
// useEventListener.js
import { onUnmounted } from 'vue'

export function useEventListener(target, event, callback) {
  onMounted(() => {
    target.addEventListener(event, callback)
  })

  onUnmounted(() => {
    target.removeEventListener(event, callback)
  })
}

// 使用
import { useEventListener } from './useEventListener'

export default {
  setup() {
    useEventListener(window, 'resize', () => {
      console.log('窗口大小改变')
    })
  }
}

6.4 避免常见错误

javascript
// ❌ 错误:在 updated 中修改响应式数据
export default {
  setup() {
    const count = ref(0)

    onUpdated(() => {
      count.value++ // 会导致无限循环
    })

    return { count }
  }
}

// ✅ 正确:使用 nextTick 或条件判断
export default {
  setup() {
    const count = ref(0)
    const isUpdating = ref(false)

    onUpdated(() => {
      if (!isUpdating.value) {
        isUpdating.value = true
        nextTick(() => {
          // 执行操作
          isUpdating.value = false
        })
      }
    })

    return { count }
  }
}

七、生命周期流程图

┌─────────────────────────────────────────────────────────────┐
│                      Vue3 生命周期流程                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────┐                                            │
│  │   setup()   │ ← 创建实例,替代 beforeCreate/created      │
│  └──────┬──────┘                                            │
│         ↓                                                   │
│  ┌─────────────────┐                                        │
│  │ onBeforeMount   │ ← 挂载前,render 首次被调用            │
│  └────────┬────────┘                                        │
│           ↓                                                 │
│  ┌─────────────────┐                                        │
│  │   onMounted     │ ← 挂载完成,DOM 可访问                 │
│  └────────┬────────┘                                        │
│           │                                                 │
│           │  ┌─────────────────────────────────┐            │
│           │  │         数据变化时               │            │
│           │  │  ┌─────────────────┐            │            │
│           │  │  │ onBeforeUpdate  │            │            │
│           │  │  └────────┬────────┘            │            │
│           │  │           ↓                     │            │
│           │  │  ┌─────────────────┐            │            │
│           │  │  │   onUpdated     │            │            │
│           │  │  └────────┬────────┘            │            │
│           │  └───────────┼─────────────────────┘            │
│           │              │                                  │
│           ↓              ↓                                  │
│  ┌─────────────────┐                                        │
│  │onBeforeUnmount  │ ← 卸载前,实例仍可用                    │
│  └────────┬────────┘                                        │
│           ↓                                                 │
│  ┌─────────────────┐                                        │
│  │   onUnmounted   │ ← 卸载完成,清理工作                    │
│  └─────────────────┘                                        │
│                                                             │
│  特殊钩子:                                                  │
│  ┌─────────────────┐  ┌─────────────────┐                   │
│  │  onActivated    │  │ onDeactivated   │ ← keep-alive      │
│  └─────────────────┘  └─────────────────┘                   │
│                                                             │
│  ┌─────────────────┐  ┌─────────────────┐                   │
│  │onRenderTracked  │  │onRenderTriggered│ ← 调试用          │
│  └─────────────────┘  └─────────────────┘                   │
│                                                             │
│  ┌─────────────────┐                                        │
│  │onErrorCaptured  │ ← 错误捕获                             │
│  └─────────────────┘                                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

八、总结

Vue3 生命周期核心变化

  1. Options API 兼容:Vue3 仍然支持 Options API 的生命周期钩子
  2. Composition API:提供 onXxx 形式的钩子函数
  3. setup 替代beforeCreatecreatedsetup 替代
  4. 命名优化beforeDestroy/destroyed 重命名为 beforeUnmount/unmounted
  5. 新增调试钩子onRenderTrackedonRenderTriggered

选择建议

  • 新项目:推荐使用 Composition API,代码组织更灵活
  • 迁移项目:可以继续使用 Options API,逐步迁移
  • 复杂组件:使用 Composition API 更容易复用和测试逻辑

基于 VitePress 的本地知识库