一、没有keep-alive组件
如果没有keep-alive组件,Vue 组件的切换遵循标准的"销毁旧组件 -> 创建新组件"流程。
这意味着:每次切换,旧组件都会彻底死亡(销毁),新组件都会重新出生(初始化)。
1. 核心结论
activated 和 deactivated:永远不会触发。这两个钩子完全依赖于 的存在。
created 和 mounted:每次进入都会触发。因为组件是全新创建的。
beforeDestroy 和 destroyed:每次离开都会触发。因为组件被彻底销毁了。
2. 详细执行流程演示
假设我们从 页面 A 切换到 页面B,然后再切回 页面 A。
- 第一步:首次进入 页面 A
- 组件实例被创建并挂载。
- beforeCreate
- created ✅ (初始化数据)
- beforeMount
- mounted ✅ (DOM 就绪,启动定时器/请求)
- 第二步:从 页面 A 切换到 页面 B
- 页面 A 被销毁,页面 B 被创建。
- 🔴 页面 A (离开时):
- beforeRouteLeave (路由守卫,如果有)
- beforeDestroy ✅ (清理工作开始)
- destroyed ✅ (实例彻底消失,数据丢失,定时器若未清除则泄漏)
- 注意:这里不会触发 deactivated
- 🟢 页面 B (进入时):
- beforeCreate
- created ✅ (重新初始化)
- beforeMount
- mounted ✅ (重新发起请求,重新绑定事件)
- 注意:这里不会触发 activated
- 第三步:从 页面 B 切回 页面 A
- 页面 B 被销毁,页面 A 重新创建(是一个全新的实例,不是之前的那个)。
- 🔴 页面 B (离开时):
- beforeDestroy
- destroyed
- 🟢 页面 A (再次进入时):
- beforeCreate
- created ✅ (再次执行!)
- beforeMount
- mounted ✅ (再次执行!)
- 结果:页面状态重置,之前输入的内容、滚动条位置、临时变量全部丢失。
二、有keep-alive组件
只要组件被 缓存,activated 钩子会在每次该组件从"隐藏状态"变为"显示状态"时执行。
这与 created 和 mounted 形成鲜明对比:
created / mounted:只在组件第一次初始化时执行一次。
activated:在组件每一次被激活(切回来)时都会执行。
1. 执行流程演示
假设你有一个列表页(List)和一个详情页(Detail),详情页被 缓存。
- 首次进入详情页:
- 触发:created → mounted → activated
- 状态:组件实例创建,DOM 挂载,变为活跃。
- 返回列表页(详情页被隐藏):
- 触发:deactivated
- 状态:组件实例保留在内存中,DOM 移除,变为非活跃。
- 再次进入详情页(从缓存恢复):
- 触发:activated ✅ (再次执行!)
- 不会触发:created, mounted ❌
- 状态:组件实例直接从内存唤醒,DOM 重新插入。
- 第三次进入详情页:
- 触发:activated ✅ (又执行了一次!)
三、总结
| 动作 | 没有 <keep-alive> (标准模式) |
有 <keep-alive> (缓存模式) |
|---|---|---|
| 首次进入 | created → mounted |
created → mounted → activated |
| 切换离开 | beforeDestroy → destroyed (组件死亡) |
deactivated (组件休眠) |
| 再次进入 | created → mounted (重生,状态重置) |
activated (唤醒,状态保留) |
| 再次离开 | beforeDestroy → destroyed |
deactivated |
| 最终销毁 | (已在第一次离开时销毁) | beforeDestroy → destroyed (当 keep-alive 移除或 exclude 时) |
activated |
❌ 从不触发 | ✅ 每次激活都触发 |
deactivated |
❌ 从不触发 | ✅ 每次隐藏都触发 |