前端难点:keep-alive 缓存什么?RouterView 的 key 为什么要带 scopeId?
摘要 :keep-alive 缓存了旧上下文数据?RouterView 的 key 必须带上 scopeId 等业务上下文。 专栏 :前端难点实战 · 阅读约 6 分钟 · 难度 :⭐⭐⭐ 实战场景:Vue3 中大型 B 端后台
一、keep-alive 解决了什么?
Vue 默认:路由切换 → 旧组件 destroy → 新组件 mount 。
用户从「设备列表」切到「告警页」再回来,列表滚动位置、筛选条件、分页全部丢失。
vue
<keep-alive :max="5">
<component :is="Component" />
</keep-alive>
缓存的是组件实例 (含 data、DOM 状态),:max="5" 限制 LRU 缓存数量,防内存膨胀。
二、业务 Layout 里的写法
vue
<RouterView v-slot="{ Component }">
<keep-alive :max="5">
<component
:is="Component"
:key="route.path + '_' + (scopeStore.mode === 'PLATFORM'
? 'platform'
: scopeStore.currentScope?.value)"
/>
</keep-alive>
</RouterView>
为什么要自定义 key?
只有 path 不够。 同一 path /app/module/list,从 上下文 A 切到 上下文 B:
- 若不换 key:keep-alive 命中旧实例 → 页面上仍是 A 站的数据
- 加上
scopeId:key 变化 → 销毁旧实例 → 挂载新实例 → 拉新 scope 数据
这是多租户 / 多站点 B 端的经典坑。
三、key 策略对照表
| key 策略 | 行为 | 适用 |
|---|---|---|
| 无 key | 同组件复用实例,仅 params 变 | 同站点详情 id 切换 |
route.fullPath |
query 变化也刷新 | 强依赖 URL 参数 |
path + scopeId |
切换 scope必刷新 | 多站点 / 多租户模式 |
| 随机 key | 每次进入都 remount | 几乎不用 |
四、keep-alive 与 Tab + 动态组件
设备分析页模式:
vue
<tabs v-model="activeTab" />
<div class="h-tabs-page-content">
<keep-alive>
<component :is="activeComponent" />
</keep-alive>
</div>
Tab 切换缓存 多个业务子模块 子页状态,避免重复请求。
注意 :<keep-alive> 要求子组件有 name (<script setup> 用 defineOptions({ name: 'XXX' })),否则 include/exclude 无法按名过滤。
五、生命周期变化
被 keep-alive 包裹的组件:
| 钩子 | 时机 |
|---|---|
onActivated |
从缓存中再次显示 |
onDeactivated |
被缓存隐藏 |
应用:
typescript
onActivated(() => {
// 回到页面时刷新告警数,而非全量 reload
refreshBadge()
})
onDeactivated(() => {
// 暂停定时器、MQTT 订阅(若页面级订阅)
})
业务系统的 MQTT 若在页面 onMounted 订阅、onUnmounted 取消,deactivated 时不会 unmount ------需在 onDeactivated 里也 unsubscribe,否则后台页仍收消息。
六、与 requestIdleCallback 埋点
Layout 在路由离开时上报停留时长:
typescript
onBeforeRouteLeave((to, from, next) => {
requestIdleCallback(() => {
sendTimeStay(from.meta.id)
}, { timeout: 2000 })
next()
})
不阻塞路由切换,利用浏览器空闲时间发埋点。
七、常见坑
- 缓存脏数据 --- key 未含业务上下文(站点、租户)
- MQTT/定时器泄漏 --- 只写了 onUnmounted,没写 onDeactivated
- max 太小 --- 用户 Tab 开多了被 LRU 踢掉,以为 keep-alive 失效
- modify props from parent --- 缓存实例状态跨会话污染
八、小结
- keep-alive = 换页不销毁,提升体验
- key = 缓存粒度,多站点必须让 key 随站点变
- 配合
onActivated/onDeactivated管理订阅和刷新
写在最后
以上难点来自真实 B 端项目工程实践。若对你有帮助,欢迎 点赞、收藏,有问题评论区交流。
发布到掘金时建议:
- 分类:前端
- 标签:前端、Vue.js、Vue Router、JavaScript
- 封面:DevTools 布局截图或代码片段图
- 摘要:复制文首「摘要」段落到编辑器摘要栏
专栏「前端难点实战」:
- 上一篇:《前端难点:ResizeObserver 在 B 端自适应布局中的正确用法》
- 下一篇:《前端难点:并发请求下全局 Loading 为什么闪烁?------ 请求计数器模式》