单 iframe 换 src 会卸载文档,WebSocket/轮询/传输状态全灭。 改为一标签一懒创建 iframe,切换只改 visibility;F5/⟳ 只 reload 激活帧。
3.5 KiB
3.5 KiB
feature, status, updated, branch, commits
| feature | status | updated | branch | commits |
|---|---|---|---|---|
| tab-keepalive | designed | 2026-09-16 | feat/tab-keepalive |
Tab Keep-Alive(多 iframe 常驻)
Report
[S1] Problem
tabs.html 用单 iframe 承载功能页,切换标签时执行 view.src = path。
这会销毁上一页的整个文档:
- WebSocket(
app-lease、调试通道)断开 setInterval/setTimeout轮询停止- 电机页 EtherCAT/WiFi 传输状态、
transport-ecat的started标志丢失 - OTA 页
ecat_load轮询、SPI 状态轮询冷启动 - 用户「调完一切、切走再切回」后连接全灭,表现为界面假死/全
--
外壳自身的 app-lease.js 仍在,但功能页内的连接与状态无法幸存。
这是结构性缺陷,不是某个页面的 bug。
[S2] Design
外壳:一标签一 iframe,只 show/hide
TABS每项对应一个懒创建 iframe(class="page-frame",data-page)。- 首次进入某标签才
src=page;之后切换只改可见性,不改 src、不 remove。 - 宿主容器
id="viewHost"(保留data-shell语义:注入脚本用#viewHost判定外壳)。 - 激活帧:
visibility:visible; pointer-events:auto;非激活:visibility:hidden; pointer-events:none。 不用display:none——部分引擎对 display:none iframe 的定时器/绘制更狠;visibility+ 绝对定位铺满即可。 - 切换时同步
localStorage.dcu_tab(沿用现有键与pageToTab迁移)。
状态保全契约
| 状态 | 保活后 |
|---|---|
| 功能页内 WS / 轮询 / Module 全局 | 留在各自 iframe 文档内,切走不断 |
外壳 app-lease |
仍由 tabs.html 自持(覆盖整个窗口) |
ecat_native 后台 PDO 循环 |
服务端 + 租约决定,与是否隐藏无关 |
| F5 / ⟳ | 只 reload 激活 iframe,不重载外壳(否则全部保活帧被销毁) |
注入刷新脚本(esp32_server.py _RELOAD_SNIPPET)
reloadCur():优先document.querySelector('.page-frame.active');无则退化location.reload()。- 外壳判定:
#viewHost存在(替代原#viewiframe 的语义)。 - 功能页内(非 TOP)行为不变:去掉悬浮钮,覆写
_blank。
导航与高亮
- 点击标签 →
go(page):确保帧存在 → 激活目标 → 其它帧隐藏。 - iframe
load:若 pathname 映射到某 TAB,更新外壳高亮与dcu_tab; 不因非激活帧的延迟 load 误抢激活(仅当该帧已是 active 才写dcu_tab)。 - 未知页(页内跳到未登记 html):仍留在当前 iframe 内显示,外壳不高亮新标签。
内存
用户裁定「全部标签常驻」。6 个功能页同时活着的代价可接受; 不引入 LRU 卸载(卸载即回到现在的病)。
[S3] Out of Scope
- 不合并成 SPA、不把连接迁到外壳进程
- 不改各页内部轮询/传输实现
- 不改服务端租约协议
- 不做「后台页降频」策略(浏览器 Page Visibility 自带节流即可)
Tasks
- T1:
tabs.html多 iframe 宿主 + 懒创建 + show/hide 切换 — acceptance: 切走再切回,OTA/电机页的轮询与 WS 仍在,无需重新连接 (covers: S2) - T2:
esp32_server.py注入的 F5/⟳ 只刷新激活帧 — acceptance: 外壳按 F5 仅重载当前标签文档,其它标签 iframe 仍在 DOM 且未 reload (covers: S2) - T3: 语法/手工验收路径 — acceptance:
node --check若适用;人工路径:开 OTA→电机→切回 OTA,指标不全灭 (covers: S2)