liuyun eed300474e
Some checks are pending
CI / backend (push) Waiting to run
CI / frontend (push) Waiting to run
docs(spec): 归档 multi-tab-keep-alive + 同步布局多页签 keep-alive 主 spec
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-11 22:13:47 +08:00

2.3 KiB
Raw Blame History

Context

多页签由 stores/modules/tabs.ts 按 path 追踪(持久化),layouts/default.vue 的 activePath watch 调 addTab,<router-view /> 直接渲染。菜单页面均为 index.vue(<script setup> 无显式 name),故 keep-alive 无法按组件名区分。动机见 proposal.md - Why。

Goals / Non-Goals

Goals:

  • 布局内菜单页面切换页签保留状态,关闭页签销毁状态。
  • keep-alive 按页面可配置:默认开启,页面可经路由 meta 关闭。

Non-Goals:

  • 不缓存空白布局页(login/register/forgot-password/force-change-password/403,均不在本布局)。

Decisions

D1 — 缓存标识 = 组件 name(路径末段 kebab)

给 11 个菜单页面补 defineOptions({ name }),name 取路径末段 kebab-case(/→dashboard、/system/user→user、/monitor/login-log→login-log…),天然唯一无冲突。

  • 备选:用 SFC 文件名派生(全是 index)——冲突,否决。

D2 — 默认缓存,路由 meta 可关闭(用户已拍板 opt-out)

页面默认缓存;在 <route> 里声明 meta.keepAlive: false 即关闭缓存。TabItem 新增 keepAlive 字段(addTab 时取 route.meta.keepAlive !== false)。

D3 — 布局 keep-alive + include 由「打开且未关闭缓存」的页签推导

layouts/default.vue 将 <router-view /> 改为:

<router-view v-slot="{ Component, route }">
  <keep-alive :include="cachedNames">
    <component :is="Component" :key="route.path" />
  </keep-alive>
</router-view>

cachedNames = tabsStore.tabs.filter(t => t.keepAlive).map(t => pathToName(t.path)),pathToName 从 tabs store 导出。

D4 — 关闭页签 = 移出 include = 销毁

关闭页签即从 tabs 移除,cachedNames 不再含该 name,keep-alive 自动销毁缓存实例;重新打开时重建(重建后重新加载数据)。

Risks / Trade-offs

  • [页面 name 与 pathToName 不一致 → 缓存静默失效] → 11 个 name 与 pathToName 采用同一约定,并在 type-check 外靠冒烟验证。
  • [缓存页面数据陈旧] → 既有 useRequest 已在进入页面时按需拉取;重建/重新打开时重新请求,不影响正确性。

Migration Plan

无数据迁移;纯前端,回滚即撤销。

Open Questions

无。