前端难点: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 为什么闪烁?------ 请求计数器模式》
相关推荐
鱼人1 小时前
CSS 变量:一个变量救你一百次复制粘贴
前端
长大19881 小时前
CSS 到底是什么?和 HTML 的区别一次讲清楚
前端
禅思院1 小时前
路由性能优化终极指南:从懒加载漏洞到边缘渲染的架构跃迁
前端·架构·前端框架
怕浪猫1 小时前
Electron 开发实战(十六):总结与展望|生态现状、框架对比、行业趋势与学习指南
前端·javascript·electron
文心快码BaiduComate1 小时前
Comate 搭载GLM-5.2:百万上下文,稳定支撑长程任务
前端·程序员·开源
星栈1 小时前
Dioxus 的 `rsx!` 语法:如果你会 React,上手确实特别快
前端·前端框架
Momo__1 小时前
TypeScript NoInfer<T>——精准控制泛型推断的工具类型
前端·typescript
lichenyang4532 小时前
从 Web 容器开始,理解 ASCF 元服务开发
前端