彻底搞懂 Vue 生命周期:从 created 到 unmounted 的完整指南

原文链接:mp.weixin.qq.com/s/SsapfXpYO...

你是不是也曾经在 Vue 项目中遇到过这样的问题:在 mounted 钩子里获取 $refs,结果发现是 undefined?或者搞不清楚到底该在 created 还是 mounted 里发起数据请求?

别担心,今天我就带你彻底搞懂 Vue 的生命周期,让你再也不踩这些坑!

Vue 生命周期流程

想象一下,一个 Vue 组件就像一个人的人生历程:

  • 出生前(beforeCreate):还没任何属性,连 data 都没有
  • 婴儿期(created):有了 data 和 methods,但还没挂载到页面上
  • 上学前(beforeMount):准备挂载到 DOM,但还没真正显示
  • 成年工作(mounted):已经在页面上显示了,可以操作 DOM 了
  • 更新阶段(beforeUpdate/updated):数据变化时的反应
  • 退休(beforeUnmount/unmounted):组件被销毁前的清理工作

是不是一下子好理解多了?

Vue 2 和 Vue 3 的生命周期对比

很多人在用 Vue 3 时发现,以前熟悉的 beforeDestroy 和 destroyed 不见了,变成了 beforeUnmount 和 unmounted。其实功能是一样的,只是名字更准确了。

Vue 2 用的是选项式 API,生命周期钩子直接写在 options 里。Vue 3 兼容这种方式,但更推荐用组合式 API,在 setup 函数里使用生命周期钩子。

最常用的几个钩子,到底该怎么用?

created:最早的初始化时机

created 钩子在组件实例创建完成后立即调用,这时候已经可以访问到 data、methods 等,但还没挂载到 DOM 上。

javascript 复制代码
export default {
  data() {
    return {
      userList: []
    }
  },
  async created() {
    // 在这里发起数据请求很合适
    // 因为组件已经初始化完成,但还没渲染到页面上
    try {
      const response = await fetch('/api/users')
      this.userList = await response.json()
    } catch (error) {
      console.error('获取用户列表失败:', error)
    }
  }
}

mounted:操作 DOM 的最佳时机

mounted 在组件挂载到 DOM 后调用,这时候可以安全地操作 DOM 元素了。

但这里有个常见陷阱:有时候在 mounted 里获取 $refs 却是 undefined!

javascript 复制代码
export default {
  mounted() {
    // 这里可以操作 DOM 了
    console.log('组件已挂载')
    
    // 但要注意:如果组件里有 v-if 条件渲染
    // 可能某些 $refs 还是拿不到
    if (this.$refs.myButton) {
      this.$refs.myButton.addEventListener('click', this.handleClick)
    }
  },
  methods: {
    handleClick() {
      console.log('按钮被点击了')
    }
  }
}

为什么有时候 $refs 是 undefined?通常是因为:

  1. 元素被 v-if 控制,初始条件为 false
  2. 在元素渲染完成前就尝试访问 $refs
  3. 组件还未完全挂载完成

解决办法是用 $nextTick 确保 DOM 更新完成后再操作:

javascript 复制代码
export default {
  mounted() {
    this.$nextTick(() => {
      // 现在肯定能拿到 $refs 了
      if (this.$refs.myInput) {
        this.$refs.myInput.focus()
      }
    })
  }
}

updated:数据变化后的操作

updated 在数据更改导致的 DOM 更新完成后调用,但要小心不要在这里修改状态,否则可能导致无限循环!

javascript 复制代码
export default {
  data() {
    return {
      count: 0
    }
  },
  updated() {
    // 这里可以获取更新后的 DOM 状态
    console.log('数据更新了,当前count:', this.count)
    
    // 危险操作:可能引起无限更新循环
    // this.count++ 
    
    // 安全操作:只是读取不修改
    const element = document.getElementById('counter')
    if (element) {
      console.log('元素内容:', element.textContent)
    }
  }
}

unmounted:清理工作的最后机会

在 Vue 3 中,用 unmounted 替代了 Vue 2 的 destroyed,用于执行清理操作,比如移除事件监听器、取消定时器等。

javascript 复制代码
import { onUnmounted } from 'vue'

export default {
  setup() {
    let intervalId = null
    
    const startTimer = () => {
      intervalId = setInterval(() => {
        console.log('定时器执行中...')
      }, 1000)
    }
    
    onUnmounted(() => {
      // 组件销毁前清除定时器,避免内存泄漏
      if (intervalId) {
        clearInterval(intervalId)
        console.log('定时器已清理')
      }
    })
    
    return {
      startTimer
    }
  }
}

实际开发中的常见场景

场景一:何时发起数据请求?

通常建议在 created 中发起数据请求,因为这时候组件已经初始化完成,可以更早地开始获取数据,减少用户等待时间。

但有些特殊情况需要在 mounted 中请求,比如需要获取元素尺寸等 DOM 信息的情况。

场景二:监听窗口大小变化

javascript 复制代码
export default {
  data() {
    return {
      windowWidth: 0
    }
  },
  mounted() {
    this.windowWidth = window.innerWidth
    window.addEventListener('resize', this.handleResize)
  },
  beforeUnmount() {
    // 一定要记得移除监听,避免内存泄漏
    window.removeEventListener('resize', this.handleResize)
  },
  methods: {
    handleResize() {
      this.windowWidth = window.innerWidth
    }
  }
}

场景三:集成第三方库

很多第三方库(如图表库、地图库)需要在 DOM 可用后才能初始化,这时候 mounted 是最合适的时机。

javascript 复制代码
export default {
  mounted() {
    // 初始化图表
    this.initChart()
  },
  methods: {
    initChart() {
      // 假设使用 echarts
      const chart = echarts.init(this.$refs.chartContainer)
      chart.setOption({
        // 图表配置
        series: [{
          type: 'bar',
          data: [10, 20, 30, 40, 50]
        }]
      })
    }
  }
}

避免这些生命周期陷阱

  1. 不要在 updated 中修改状态 - 这可能导致无限更新循环

  2. 记得清理副作用 - 事件监听器、定时器、订阅等都要在 unmounted 中清理

  3. 理解异步更新队列 - Vue 会批量执行更新,使用 $nextTick 确保 DOM 更新完成

  4. 注意 v-if 对生命周期的影响 - 被 v-if 控制的组件会完全销毁和重新创建,而不是隐藏和显示

总结一下

Vue 生命周期就像是组件的"人生阶段",每个阶段都有其特定的用途和注意事项:

  • created:初始化数据,发起请求
  • mounted:操作 DOM,集成第三方库
  • updated:响应数据变化后的 DOM 更新
  • unmounted:清理工作,避免内存泄漏

最重要的是理解每个钩子的执行时机和适用场景,这样在开发中就能做出正确的选择。

你在使用 Vue 生命周期时还遇到过哪些坑?或者有什么特别的使用技巧?欢迎在评论区分享你的经验!

对了,如果你觉得这篇文章对你有帮助,记得点赞收藏,下次遇到生命周期的问题就不会迷路啦~

相关推荐
GHOME2 小时前
复习-网络协议
前端·网络协议·面试
秦清2 小时前
组态可视化软件【导入属性】
前端·javascript·后端
小桥风满袖2 小时前
极简三分钟ES6 - 函数的参数
前端·javascript
艾小码2 小时前
只会npm install?这5个隐藏技巧让你效率翻倍!
前端·npm·node.js
hwjfqr3 小时前
VSCode终端中文乱码问题解决
前端·后端
3 小时前
前端页面空白监控:从检测到溯源的全链路实战方案
前端
妮妮喔妮3 小时前
如何把HTML转化成桌面Electron
前端·javascript·electron
日月晨曦3 小时前
React 在线 playground 实现指南:让代码在浏览器里「原地爆炸」的黑科技
前端·react.js
南北是北北3 小时前
Flow 里的上游/下游
前端·面试