Vue 生命周期与 keep-alive:我用真实项目终于搞清楚了
"生命周期"这个词在 Vue 教程里会很早出现,但很多人学了之后还是一知半解。 因为光看文档,没有感觉。这篇文章想用真实项目代码,帮你把它们"落地"。
先说一个语言上的误导
"生命周期" 这个词,听起来像是整个项目从打开到关闭的一段大流程。
但实际上,它属于每一个组件。
正确的理解是:
每个 Vue 组件实例,都有自己的出生、挂载、更新、离开、缓存激活的过程。 这些阶段,Vue 会自动调用对应的钩子函数,给你一个"插队"的机会。
🗓️ 最常用的几个生命周期钩子
created —— 数据准备好了,但页面还没画出来
✅ 适合做什么:
- 发起不依赖 DOM 的数据请求
- 初始化变量
- 读取 Vuex / props
mounted —— 页面已经渲染出来了,DOM 摸得到了
✅ 适合做什么:
- 操作 $refs(真实 DOM)
- 绑定滚动、键盘、resize 事件
- 初始化第三方 JS 库(图表、播放器、WebSocket 等)
beforeDestroy / destroyed —— 组件要销毁了
✅ 适合做什么:
- 清除定时器
- 解绑事件监听
- 关闭 WebSocket
- 释放资源
activated —— keep-alive 缓存的页面"重新回来了"
✅ 适合做什么:
- 每次回到这个页面时,重新拉数据
- 恢复某些需要刷新的状态
deactivated —— keep-alive 缓存的页面"离开了,但没销毁"
✅ 适合做什么:
- 暂停正在播放的音频
- 停止轮询
- 暂停实时监听
🔁 keep-alive 会改变什么
keep-alive 是 Vue 的内置组件,作用是缓存被包住的组件实例。
没有 keep-alive 的情况下,离开一个页面 = 销毁这个组件。
有了 keep-alive,离开页面之后组件不一定被销毁,而是被"冷冻"起来:
首次进入缓存页:
created → mounted → activated
离开缓存页(不销毁):
deactivated
再次进入缓存页:
activated ← 直接从这里开始,跳过了 created 和 mounted!
这就是为什么你会在缓存相关的组件里,经常看到 activated 而不是 created。
🔧 用真实项目代码来拆解
根实例的 created:应用一启动就执行一次
// src/main.js
new Vue({
router,
store,
render: h => h(App),
created() {
// 这里的 created 只在"整个应用开机"时执行一次
store.commit('businessCoulmn/setWorkDetail', ''); // 重置业务状态
store.commit('instantMessaging/setScreenfullBut', false); // 重置 IM 全屏状态
store.commit('siteBar/addMenu', router); // 注入动态菜单
},
}).$mount('#app');
这里的 created 是根实例的生命周期,属于"整个应用开机初始化",不属于任何页面。
登录页的 created + mounted:先清状态,再做页面效果
created:
- 清空本地存储
- 重置菜单和 tab
- 清空 token
mounted:
- 启动背景动画效果
典型用法:
created适合"先把旧状态清干净"mounted适合"页面展示出来之后做的事情"
IM 页面入口:created 做初始化
created:
1. 拿老师的聊天账号
2. 拿 IM 配置
3. 初始化 TIM SDK
4. 绑定 TIM 事件
5. 登录 IM
为什么用 created 而不是 mounted?
因为这些步骤不需要操作 DOM,提前在 created 里做,能更快完成初始化。
IM 布局组件:mounted 初始化 WebSocket
mounted:
- 初始化 WebSocket 连接
beforeDestroy:
- 关闭 WebSocket
- 停掉轮询
mounted 之所以适合初始化 WebSocket,是因为:
- WebSocket 有时候需要操作 DOM
mounted保证页面已经渲染,更安全
beforeDestroy 负责配套的清理工作,避免资源泄漏。
ConversationList 用 activated 而不是 created,是因为……
// src/components/.../ConversationList/index.vue
activated() {
this.handleGetWechatStudentList(); // 每次"回到页面"时刷新数据
}
为什么不用 created?
因为这个组件被 keep-alive 包着。
- 第一次进来会走
created - 切走再切回来,
created不会重新触发 - 但
activated每次回来都会触发
所以这里的逻辑是:
created → 第一次初始化
activated → 每次"回来"时刷新数据
这是 keep-alive 场景下非常经典的写法。
MessageWindow 用 deactivated,是因为……
// src/components/.../MessageWindow/index.vue
deactivated() {
this.handlePauseAudio(); // 离开页面时暂停音频
}
为什么不用 beforeDestroy?
因为这个组件被缓存了,切走页面时不是真正销毁,不会触发 beforeDestroy。
会触发的是 deactivated,专门处理"缓存页离开时的收尾动作"。
🔄 用一次完整流程来理解
1. 用户打开项目
└─ main.js 创建根实例
└─ 根实例 created 执行(初始化菜单、重置 IM 状态)
2. 用户登录
└─ login.vue created 清空旧数据
└─ login.vue mounted 显示背景动画
3. 进入 IM 聊天页
└─ instant-messaging/index.vue created 做 IM 初始化
└─ Layout/index.vue mounted 初始化 WebSocket
4. 用户切走页面
└─ 缓存页面 → 触发 deactivated(不销毁)
└─ 非缓存页面 → 触发 beforeDestroy(销毁)
5. 用户切回 IM 页面
└─ 触发 activated
└─ ConversationList 重新拉数据
⚠️ 不要混淆的三个东西
| 概念 | 是什么 |
|---|---|
| 生命周期 | 组件的出生、挂载、更新、离开、重现的各个阶段 |
| watch | 监听某个数据变化,不是生命周期 |
| keep-alive | 缓存机制,它会改变组件的生命周期表现 |
keep-alive 的存在,让 deactivated / activated 有意义。
没有 keep-alive 包着的组件,这两个钩子永远不会触发。
🏁 一句话总结
Vue 生命周期不是"整个项目统一跑一遍的流程"
而是"每个组件实例自己的阶段变化"
keep-alive 改变的是"离开"和"回来"的行为:
- 离开时不销毁 → deactivated
- 回来时不重建 → activated
所以:
created / mounted → 用于首次初始化
activated → 用于每次回来时刷新
deactivated → 用于离开时收尾
beforeDestroy → 用于真正销毁时清理
这是 Vue2 学习系列第四篇。
下一篇:Vue、SPA、MPA 傻傻分不清?一篇弄清楚三者的关系。