Vue 生命周期:深入理解组件从诞生到销毁的全过程

383 阅读3分钟

Vue 生命周期:深入理解组件从诞生到销毁的全过程

在 Vue 开发中,生命周期是组件从创建、挂载、更新到销毁的完整过程。每个阶段都有对应的钩子函数,让开发者能在特定时机执行代码。深入理解生命周期是掌握 Vue 的核心关键。

一、生命周期四大阶段

1. 创建阶段(Initialization)

  • beforeCreate 组件实例刚创建,数据观测和事件机制尚未初始化

    beforeCreate() {
      console.log(this.message) // undefined
      console.log(this.$el)     // undefined
    }
    
  • created 实例创建完成,已完成数据观测,属性和方法的运算,可访问数据和方法(最常用的异步请求时机),但尚未挂载到 DOM

    created() {
      console.log(this.message) // "Hello Vue!"
      this.fetchData() // 发起API请求
    }
    

2. 挂载阶段(DOM Insertion)

  • beforeMount 模板编译完成,但尚未渲染到页面

    beforeMount() {
      console.log(document.getElementById('app')) // null
    }
    
  • mounted 实例已挂载到 DOM,可操作 DOM 元素

    mounted() {
      console.log(this.$el) // 获取DOM节点
      this.initChart()      // 初始化ECharts图表
    }
    

3. 更新阶段(Re-rendering)

  • beforeUpdate 在数据发生改变后,DOM 被更新之前被调用数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前

    export default {
      data() {
        return { count: 0 }
      },
      methods: {
        increment() {
          this.count++; // 数据立即更新
        }
      },
      beforeUpdate() {
        console.log("beforeUpdate - 数据已新:", this.count); // 输出新值(如 1)
        console.log("DOM 内容仍是旧的:", document.getElementById("count").textContent); // 输出旧值(如 0)
      }
    }
    

    关键点:

    • beforeUpdate 中的数据状态: 数据确实已完成更改(组件实例的 this.xxx 已是新值),但 DOM 尚未更新,因此视图与数据不同步
    • ❌ 常见误解: 错误认为 "beforeUpdate 时数据还未更新",实际上数据变更发生在 beforeUpdate 之前
  • updated 数据更改导致的 DOM 更新完成后

    updated() {
      // 注意:避免在此处修改状态,可能导致无限循环!
      console.log('DOM已更新')
    }
    

4. 销毁阶段(Teardown)

对比项Vue 2Vue 3说明
钩子命名beforeDestroy / destroyedbeforeUnmount / unmountedVue 3 使用更准确的术语("unmount" 而非 "destroy")。
组合式 API 影响setup() 内部可使用 onBeforeUnmount 和 onUnmountedVue 3 的组合式 API 提供了更灵活的销毁逻辑管理方式。
异步清理同步销毁支持异步组件卸载(<Suspense>Vue 3 的异步组件卸载机制更完善。
事件监听器自动清理需要手动移除在 setup() 中使用 onUnmounted 自动清理 watch 和 computedVue 3 的组合式 API 更易于管理副作用。
  • beforeUnmount 实例销毁前,资源清理的最佳时机

    beforeUnmount() {
      clearInterval(this.timer)  // 清除定时器
      window.removeEventListener('resize', this.handleResize) // 移除事件监听
    }
    
  • unmounted 实例完全销毁,所有绑定和子实例被移除

    unmounted() {
      console.log('组件已销毁') 
    }
    

二、特殊场景的生命周期钩子

1. keep-alive 相关

  • activated 被缓存的组件激活时调用(如从后台切回前台)

    activated() {
      this.startAutoRefresh() // 重新启动轮询
    }
    
  • deactivated 被缓存的组件停用时调用

    deactivated() {
      this.stopAutoRefresh() // 停止后台任务
    }
    

2. 错误捕获

  • errorCaptured 捕获子孙组件的错误(Vue 2.5+)

    errorCaptured(err, vm, info) {
      console.error(`捕获到错误: ${err.toString()}`)
      this.logErrorToService(err) // 上报错误日志
      return false // 阻止错误继续向上传播
    }
    

三、生命周期流程图解

创建阶段
  ↓
beforeCreate → created(初始化数据)
  ↓
挂载阶段
  ↓
beforeMount → mounted(操作DOM)
  ↓
↻ 更新循环 ↺
beforeUpdate → updated
  ↓
销毁阶段
  ↓
beforeUnmount → unmounted

四、最佳实践与常见陷阱

  1. 异步请求放在哪里?

    • 使用 created:需要尽早获取数据时
    • 使用 mounted:需要访问 DOM 时
  2. 避免在 updated 中修改状态 可能导致无限更新循环,使用计算属性或侦听器替代

  3. 内存泄漏防范beforeDestroy 中必须清理:

    beforeUnmount() {
      // 清除定时器
      clearTimeout(this.timer)
      // 移除全局事件
      window.removeEventListener('scroll', this.handleScroll)
      // 取消未完成的异步任务
      this.cancelToken && this.cancelToken.cancel()
    }
    
  4. 父子组件生命周期顺序

    父beforeCreate → 父created → 父beforeMount 
      → 子beforeCreate → 子created → 子beforeMount → 子mounted 
      → 父mounted
    

五、Vue 3 的变化

在 Vue 3 的 Composition API 中,生命周期通过 setup() 函数访问:

import { onMounted, onUpdated } from 'vue'

setup() {
  onMounted(() => {
    console.log('组件已挂载')
  })
  
  onUpdated(() => {
    console.log('数据已更新')
  })
}

注意:beforeCreatecreatedsetup() 替代

结语

理解 Vue 生命周期如同掌握组件的"人生轨迹",能让你:

  • ✅ 精准控制异步操作时机
  • ✅ 高效管理资源和内存
  • ✅ 避免状态更新导致的意外行为
  • ✅ 优化组件性能

通过合理运用生命周期钩子,你的 Vue 应用将获得更好的可维护性和稳定性。