对于每一位 Vue 开发者来说,理解其生命周期是构建健壮、高效应用的基础。Vue 实例从诞生到消亡,会经历一系列特定的阶段,就像人生的不同时期一样。在这些阶段中,Vue 提供了特定的“钩子函数”,允许我们在恰当的时机介入并执行我们自己的代码。

今天,就让我们一起踏上这场探索 Vue 生命周期的旅程!

一、Vue 生命周期的四大阶段

一个完整的 Vue 生命周期可以分为四个主要阶段,共包含 8 个核心钩子函数:
生命周期图示

(图片来源: Vue.js 官方文档)

1. 创建 (Creation)

这个阶段负责初始化 Vue 实例,设置数据监听、计算属性、方法、侦听器等。

  • beforeCreate:

    • 时机: 实例刚刚在内存中被创建,是生命周期的第一个事件。
    • 状态: 在这个阶段,数据 ($data) 和 DOM 元素 ($el) 都尚未初始化,你无法访问它们。
    • 用途: 通常用于一些与数据和视图无关的初始化任务,比如添加一个全局事件监听或初始化一个非响应式的数据。
  • created:

    • 时机: 实例已经完成了数据观测 (data observation)、属性和方法的运算,以及 watch/event 事件回调的配置。
    • 状态: 在这个阶段,$data 已经准备就绪,你可以访问和修改数据。但是,$el (DOM 元素) 仍然不存在
    • 用途: 这是我们最常进行异步数据请求(如通过 Axios 发起 API 调用)的地方。因为此时数据已经可以被赋值,但还不需要渲染视图。

2. 挂载 (Mounting)

这个阶段将 Vue 实例与真实的 DOM 元素关联起来,并将虚拟 DOM 渲染为真实 DOM。

  • beforeMount:

    • 时机: 在相关的 render 函数首次被调用之前,即将开始把模板编译成虚拟 DOM 并挂载。
    • 状态: $data 已经存在,但 $el 仍然是虚拟的,尚未替换页面上真实的 DOM。
    • 用途: 可以在这里对 DOM 进行一些“挂载前”的最后修改,但这种情况比较少见。
  • mounted:

    • 时机: 实例已经被挂载到页面上,el 被新创建的 vm.$el 替换了。
    • 状态: 在这个阶段,$data$el 都已准备就绪。你可以完全访问和操作真实的 DOM。
    • 用途: 非常适合执行需要依赖真实 DOM 的操作,比如初始化第三方库(如 Chart.js, D3.js)、获取 DOM 元素的尺寸和位置、或手动操作 DOM。

3. 更新 (Updating)

当实例所管理的数据发生变化时,会触发这个阶段,导致虚拟 DOM 重新渲染和打补丁 (patch)。

  • beforeUpdate:

    • 时机: 当数据发生改变后,DOM 被更新之前调用。
    • 状态: 你可以访问到即将更新的数据。
    • 用途: 可以在这里获取 DOM 更新前的状态,例如保存滚动条的位置。
  • updated:

    • 时机: 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
    • 状态: 组件 DOM 已经更新完成。
    • 用途: 可以执行依赖于 DOM 更新完成后的操作。但要注意避免在此钩子中直接修改数据,否则可能会导致无限循环的更新。

4. 销毁 (Destruction)

这个阶段负责清理 Vue 实例,移除事件监听、定时器,并销毁子实例。

  • beforeDestroy (Vue 3 中为 beforeUnmount):

    • 时机: 实例销毁之前调用。
    • 状态: 在这一步,实例仍然完全可用。
    • 用途: 这是进行“善后工作”的最佳位置。例如,清除定时器 (clearInterval)解绑全局事件监听 (window.removeEventListener)、或销-/掉对第三方库实例的引用,以防止内存泄漏。
  • destroyed (Vue 3 中为 unmounted):

    • 时机: 实例销毁之后调用。
    • 状态: 调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
    • 用途: 可以用来执行一些最后的清理工作,但此时实例的大部分功能已经不可用。

二、初次加载时会发生什么?

当我们第一次进入一个页面或组件时,它会按顺序执行生命周期的前四个钩子函数,并且停留在 mounted 阶段,等待数据的变化。这个过程是:

beforeCreate -> created -> beforeMount -> mounted

  • beforeCreate: 实例被创建,但什么都没有。
  • created: 数据 ($data) 准备好了,但没有 DOM ($el)。这是发起 API 请求的好地方。
  • beforeMount: 模板已编译好,准备挂载,但 DOM 仍然是虚拟的。
  • mounted: DOM 挂载完成,数据和视图都已就绪,可以开始交互。

三、keep-alive 带来的新旅程

在某些场景下,我们希望组件在切换后能“保持活力”,而不是被销毁,以便保留它的状态或避免重新渲染。这时,Vue 的内置组件 <keep-alive> 就派上用场了。

当一个组件被 <keep-alive> 包裹时,它会多出两个专属的生命周期钩子:

  • activated:

    • 时机: 当被缓存的组件被激活(即重新显示在视图中)时调用。
    • 用途: 可以在这里重新获取数据或执行一些每次进入组件都希望执行的操作。
  • deactivated:

    • 时机: 当被缓存的组件被停用(即从视图中移除,但未销毁)时调用。
    • 用途: 可以在这里执行一些清理工作,比如清除在 activated 中创建的定时器。

重要提示: 对于被 <keep-alive> 缓存的组件,destroyed 钩子不会被调用,因为组件实例并没有被真正销毁。

总结

理解 Vue 的生命周期,就像是拿到了一张 Vue 应用运行的“地图”。它能帮助我们:

  • 正确的时间执行正确的操作
  • 高效地进行数据请求DOM 操作
  • 优雅地进行资源管理,避免内存泄漏

希望这篇博客能帮助你更好地掌握 Vue 的核心,写出更出色、更健壮的应用程序!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐