彻底搞懂 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 生命周期时还遇到过哪些坑?或者有什么特别的使用技巧?欢迎在评论区分享你的经验!

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

相关推荐
brzhang9 分钟前
ChatGPT Pulse来了:AI 每天替你做研究,这事儿你该高兴还是该小心?
前端·后端·架构
正义的大古13 分钟前
OpenLayers地图交互 -- 章节八:平移交互详解
javascript·vue.js·交互·openlayers
泉城老铁29 分钟前
springboot+vue 文件下载,实现大文件的分片压缩和下载,避免内存溢出
前端·spring boot·后端
用户2037355498129 分钟前
Vue+Node+MongoDB高级全栈开发视频教程 完整版
前端
我是天龙_绍40 分钟前
setup 函数 和 setup 语法糖
前端
泉城老铁42 分钟前
Spring Boot和Vue.js项目中实现文件压缩下载功能
前端·spring boot·后端
我是天龙_绍42 分钟前
vue3 中,setup 函数 和 <script setup> 的区别
前端
LoveEate44 分钟前
vue 在el-tabs动态添加添加table
javascript·vue.js·elementui
krifyFan1 小时前
vue3+elementPlus el-date-picker 自定义禁用状态hook 实现结束时间不能小于开始时间
前端·vue.js·elementui
一颗努力的大土豆1 小时前
关于解决switch开关属性中active-value=“1“为数值形失败的问题
javascript·vue.js·elementui