前端难点:keep-alive 缓存什么?RouterView 的 key 为什么要带 scopeId?

前端难点: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()
})

不阻塞路由切换,利用浏览器空闲时间发埋点。


七、常见坑

  1. 缓存脏数据 --- key 未含业务上下文(站点、租户)
  2. MQTT/定时器泄漏 --- 只写了 onUnmounted,没写 onDeactivated
  3. max 太小 --- 用户 Tab 开多了被 LRU 踢掉,以为 keep-alive 失效
  4. modify props from parent --- 缓存实例状态跨会话污染

八、小结

  • keep-alive = 换页不销毁,提升体验
  • key = 缓存粒度,多站点必须让 key 随站点变
  • 配合 onActivated/onDeactivated 管理订阅和刷新

写在最后

以上难点来自真实 B 端项目工程实践。若对你有帮助,欢迎 点赞、收藏,有问题评论区交流。

发布到掘金时建议

  • 分类:前端
  • 标签:前端、Vue.js、Vue Router、JavaScript
  • 封面:DevTools 布局截图或代码片段图
  • 摘要:复制文首「摘要」段落到编辑器摘要栏

专栏「前端难点实战」

  • 上一篇:《前端难点:ResizeObserver 在 B 端自适应布局中的正确用法》
  • 下一篇:《前端难点:并发请求下全局 Loading 为什么闪烁?------ 请求计数器模式》
相关推荐
小彤花园2 小时前
和 AI 结对写网站:从 JSON 到一整个工具集
前端·人工智能·程序员
RD_daoyi2 小时前
Google核心算法不再通知!全年持续滚动更新
大数据·服务器·前端·网络·搜索引擎·.net
এ慕ོ冬℘゜2 小时前
纯 CSS 实现自定义 Switch 开关(商品上下架滑块)
前端·css
再吃一根胡萝卜2 小时前
dompdf.js 分页功能完整实现指南
前端
wordbaby2 小时前
App 热更新(OTA)原理深解 —— 以 React Native 为例
前端·react native
再吃一根胡萝卜2 小时前
Vue + dompdf.js 实现简历分页导出的完整踩坑记录
前端
其美杰布-富贵-李2 小时前
第 6 篇:相机与 OrbitControls
前端·javascript·three.js
lichenyang4532 小时前
从图片生成任务到用户隔离:AIGC Creative Studio 后端与 PostgreSQL 建模实践
前端·后端
小黑技术栈3 小时前
关于前端的一些话
前端
执子念的飞鱼3 小时前
Vue 3 文件预览落地:鉴权 Blob、Worker/WASM 与内网子路径部署
vue.js·webassembly