人人都会AI编程

缓存原理与 activated /deactivated 生命周期

更新时间:2026-07-09

<KeepAlive> 是 Vue 内置的组件缓存机制。当一个被包裹的动态组件切换离开时,它不会被销毁,而是被缓存起来;等再次切换回来时,直接复用缓存的组件实例,并恢复之前的状态。

缓存原理:不销毁,只隐藏

在没有 <KeepAlive> 的情况下,切换动态组件时,离开的组件会被完整卸载(unmounted),其 DOM 被移除,组件实例被销毁,内部的所有状态丢失。下次再切换回来,必须从头初始化。

<KeepAlive> 改变了这个流程:

  1. 第一次渲染:组件正常创建、挂载、触发 setuponMounted
  2. 切换离开时<KeepAlive> 并不会调用 unmount,而是将组件实例连同其关联的 DOM 节点移入一个内存缓存池。此时组件变为“非活跃”状态,但它的所有响应式数据、DOM 状态(如输入框内容、滚动位置)、定时器等都仍然存在。
  3. 再次切换回来时:直接从缓存池中取出之前的组件实例,重新插入到 DOM 树中,不重新执行 setup,也不重新创建组件。

这样做的本质是以空间换时间:消耗少量内存来避免重复的组件创建和销毁开销,适用于在多个视图间频繁切换但数据需要保留的场景。

activated 与 deactivated:缓存感知的生命周期

因为组件在缓存期间并没有被销毁,常规的 onMounted / onUnmounted 无法反映切换过程。Vue 专门提供了两个钩子来响应“活跃”与“非活跃”的切换:

  • onActivated(或选项式 activated):当被缓存的组件重新激活时调用。可以在这里执行数据刷新、重新启动定时器等操作。
  • onDeactivated(或选项式 deactivated):当组件被缓存起来时调用。适合在这里清除定时器、暂停动画、保存临时的交互状态。

一个完整的生命周期调用顺序示例:

首次进入组件 → setup → onMounted → onActivated
切换到其他组件 → onDeactivated
切回当前组件 → onActivated (不会再次调用 onMounted)

注意onActivatedonDeactivated 只在被 <KeepAlive> 包裹的组件中才会被触发。对于直接挂载或卸载的组件,这两个钩子不会被调用。

实用场景

  • 表单草稿保留:用户在一个多步骤步骤表单的第 2 步填写了一半,不小心切到第 1 步查看又切回来,输入的内容还保持原样,不需要用户重新填写。
  • 滚动位置保持:一个资讯列表,用户滚动到第 3 页,点进详情后再返回列表,滚动条依然在原来的位置。
  • 频繁切换的 Tab 页面:后台管理系统常见的 Tab 标签页,每个标签下是独立的查询结果或图表,缓存后可避免每次切换都重新请求数据、重新渲染图表。

常用配置项

  • include / exclude:通过字符串、正则或数组来指定哪些组件需要被缓存,哪些不需要。例如:
  <KeepAlive include="Home,About">
    <component :is="currentView" />
  </KeepAlive>
  
  • max:限制缓存池的最大数量。当缓存实例超过该数量时,最早且未被再次访问的组件实例会被销毁,避免内存无限增长。

注意事项

  • 如果组件已经缓存并再次激活,setup 不会重复执行,因此不能依赖 setup 中的初始化逻辑来刷新数据,应该把刷新逻辑放在 onActivated 中。
  • 组件内部的定时器或异步请求如果在 onDeactivated 中没有被清理,可能会导致内存浪费甚至 bug,建议成对处理:
  let timer
  onActivated(() => {
    timer = setInterval(() => { ... }, 1000)
  })
  onDeactivated(() => {
    clearInterval(timer)
  })
  
  • 当组件被缓存时,其 DOM 仍在内存中,但不可见,如果组件依赖 nextTick 去获取元素尺寸,记得在 onActivated 中重新获取。

小结

<KeepAlive> 的核心价值在于在组件切换时保留用户的操作状态和 UI 状态,避免因销毁重建带来的性能损耗和数据丢失。activateddeactivated 则是与这套缓存机制配套的生命周期钩子,让开发者可以精确控制组件“休眠”与“唤醒”时的行为。