Vue生命周期执行顺序详解:从创建到销毁的完整流程解析

摘要:在Vue开发中,你是否遇到过这些问题:在created钩子中操作DOM却获取不到元素?父子组件的mounted钩子到底谁先执行?在beforeDestroy中清理资源却发现组件已被移除?

在Vue开发中,你是否遇到过这些问题:

  • 在created钩子中操作DOM却获取不到元素?

  • 父子组件的mounted钩子到底谁先执行?

  • 在beforeDestroy中清理资源却发现组件已被移除?

这些问题的核心在于对Vue生命周期执行顺序的理解不足。本文将深入解析Vue2和Vue3的生命周期流程,帮助你在实际开发中精准掌控组件行为。


一、Vue2生命周期完整流程

关键阶段详解:

  1. 创建阶段

    beforeCreate() {
      // 此时无法访问data和methods
      console.log('beforeCreate:', this.message) // undefined
    }
    created() {
      // 可访问数据但DOM未生成
      console.log('created:', this.message) // 数据可用
      console.log('DOM:', this.$el) // undefined
    }
  2. 挂载阶段

    beforeMount() {
      // 模板编译完成但未挂载到页面
      console.log('beforeMount:', this.$el.innerHTML) // 旧内容
    }
    mounted() {
      // DOM完全可用,可进行DOM操作
      console.log('mounted:', this.$el.textContent) // 渲染后内容
    }
  3. 更新阶段

    beforeUpdate() {
      // 数据已改变但DOM未更新
      console.log('beforeUpdate DOM:', this.$el.textContent) // 旧内容
    }
    updated() {
      // DOM更新完成
      console.log('updated DOM:', this.$el.textContent) // 新内容
    }
  4. 销毁阶段

    beforeDestroy() {
      // 组件销毁前,可清理定时器
      console.log('beforeDestroy:', this._isBeingDestroyed) // false
      clearInterval(this.timer)
    }
    destroyed() {
      // 组件完全销毁
      console.log('destroyed:', this._isBeingDestroyed) // true
    }


二、Vue3组合式API生命周期变化

Vue2到Vue3映射关系:

Vue2选项式APIVue3组合式API
beforeCreate使用setup()代替
created使用setup()代替
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeDestroyonBeforeUnmount
destroyedonUnmounted

组合式API执行顺序示例:

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

export default {
  setup() {
    console.log('setup - 替代created')
    
    onBeforeMount(() => {
      console.log('onBeforeMount')
    })
    
    onMounted(() => {
      console.log('onMounted')
    })
    
    // 其他钩子同理...
    
    return {}
  }
}


三、父子组件生命周期执行顺序(重要!)

组件嵌套时的执行流程:

flowchart TD
    A[父beforeCreate] --> B[父created]
    B --> C[父beforeMount]
    C --> D[子beforeCreate]
    D --> E[子created]
    E --> F[子beforeMount]
    F --> G[子mounted]
    G --> H[父mounted]

实际代码验证:

<!-- Parent.vue -->
<script>
export default {
  beforeCreate() { console.log('父 beforeCreate') },
  created() { console.log('父 created') },
  beforeMount() { console.log('父 beforeMount') },
  mounted() { console.log('父 mounted') },
}
</script>

<template>
  <Child />
</template>

<!-- Child.vue -->
<script>
export default {
  beforeCreate() { console.log('子 beforeCreate') },
  created() { console.log('子 created') },
  beforeMount() { console.log('子 beforeMount') },
  mounted() { console.log('子 mounted') },
}
</script>

输出顺序:

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

四、异步操作对生命周期的影响

  1. created中发起异步请求

    created() {
      fetchData().then(data => {
        // 此时可能已进入mounted阶段
        this.data = data
      })
    }
  2. mounted中的DOM操作陷阱

    mounted() {
      // 若子组件异步加载,此时可能未渲染
      this.$nextTick(() => {
        // 确保DOM更新后执行
        this.initThirdPartyLib()
      })
    }
  3. 更新阶段的数据竞态问题

    updated() {
      // 避免在此处直接修改状态,可能导致无限循环
      // 正确做法:使用计算属性或侦听器
    }


五、常见错误与解决方案

错误1:在created中操作DOM

created() {
  // 错误!此时DOM尚未创建
  document.getElementById('myEl').style.color = 'red'
}

✅ 解决方案:将DOM操作移至mounted钩子

错误2:忽略异步组件的生命周期

<template>
  <AsyncComponent v-if="show" />
</template>

<script>
export default {
  methods: {
    loadComponent() {
      this.show = true
      // 错误!此时异步组件可能尚未加载完成
      this.$nextTick(() => {
        // 正确:等待组件完全挂载
      })
    }
  }
}
</script>

错误3:在beforeDestroy中访问已销毁元素

beforeDestroy() {
  // 危险操作:此时DOM元素可能已被移除
  this.$el.removeEventListener('click', this.handler)
}

✅ 解决方案:在mounted中添加监听,在beforeUnmount中移除


六、生命周期最佳实践

  1. 数据初始化

    created() {
      // 初始化非响应式数据
      this.timer = null
    }
  2. API请求时机

    created() {
      // 尽早发起请求,减少用户等待时间
      this.loadUserData()
    }
  3. 第三方库初始化

    mounted() {
      // DOM就绪后初始化
      this.chart = echarts.init(this.$el)
    },
    beforeUnmount() {
      // 清理资源防止内存泄漏
      this.chart.dispose()
    }
  4. 性能敏感操作

    updated() {
      // 避免在此处执行重操作
      // 使用watch深度监听替代
    }


七、特殊场景生命周期

  1. keep-alive组件专属钩子

    activated() {
      // 组件被激活时调用
      this.startAnimation()
    },
    deactivated() {
      // 组件被停用时调用
      this.pauseAnimation()
    }
  2. 错误捕获钩子

    errorCaptured(err, vm, info) {
      // 捕获子组件错误
      logErrorToService(err)
      return false // 阻止错误继续向上传播
    }


总结:生命周期使用核心要点

  1. 创建阶段

    • beforeCreate:避免操作数据

    • created:安全访问数据,可发起API请求

  2. 挂载阶段

    • beforeMount:极少使用

    • mounted:执行DOM操作,初始化第三方库

  3. 更新阶段

    • beforeUpdate:获取更新前DOM状态

    • updated:避免修改响应式数据

  4. 销毁阶段

    • beforeUnmount(Vue3)/beforeDestroy(Vue2):清理定时器、事件监听

    • unmounted(Vue3)/destroyed(Vue2):确认组件已卸载

父子组件顺序口诀
父创建 → 子创建 → 子挂载 → 父挂载
父更新 → 子更新 → 子完成 → 父完成
父销毁 → 子销毁 → 子完成 → 父完成

理解生命周期执行顺序是成为Vue高级开发者的必备技能。合理利用各生命周期钩子,既能避免常见错误,又能优化组件性能。建议在开发复杂组件时,配合console.log输出各阶段状态,加深对执行流程的理解。

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://shenqiku.cn/article/FLY_12739