d74e84c87b
preserve xterm viewport intent when switching terminal tabs so bottom-pinned sessions stay pinned and manually scrolled sessions keep their history position unify viewport restoration across activation, fit, and resize paths to avoid losing scroll state after terminal reflow
3.0 KiB
3.0 KiB
变更提案: terminal-tab-scroll-restore
元信息
类型: 缺陷修复
方案类型: implementation
优先级: P1
状态: 已完成
状态说明: 已完成 Terminal.vue 视口恢复修复与构建验证,待归档
创建: 2026-03-25
1. 需求
背景
在 /workspace 切换不同终端标签时,xterm 视口偶发没有停留在底部,导致最新输出不在可见区域底部。用户期望保留“看历史”和“追最新输出”两种不同滚动意图。
目标
- 修复终端标签切换后的视口恢复行为。
- 如果终端切换前原本就在底部附近,则重新激活后自动贴底。
- 如果用户切换前主动上翻查看历史,则重新激活后保留原滚动位置。
约束条件
范围约束: 优先限制在前端终端组件与现有会话终端实例管理链路
实现约束: 不改动 SSH 数据流、标签切换语义和后端协议
体验约束: 不得把所有终端切换都强制滚到底部
兼容约束: 兼容现有 keep-alive + v-show 的终端挂载方式
验收标准
- 切换终端标签时,原本贴底的终端重新显示后仍贴底
- 切换终端标签时,原本已上翻查看历史的终端重新显示后保留原滚动位置
- 终端
fit、重激活与滚动恢复逻辑不引入明显回归 - 前端构建通过
2. 方案
技术方案
在 Terminal.vue 内为每个终端实例记录当前视口行号和“是否应贴底”的本地状态。使用 xterm 的 buffer.active.ydisp / baseY 判断当前距离底部的行数,并定义一个“小于等于阈值即视为贴底”的规则。终端重新激活或执行 fit 时,不再只做尺寸重算,而是按切换前快照恢复:贴底终端调用 scrollToBottom(),上翻终端调用 scrollToLine(savedYdisp) 恢复到原位置。
影响范围
涉及模块:
- frontend: Terminal.vue 终端视口恢复逻辑
预计变更文件: 1
风险评估
| 风险 | 等级 | 应对 |
|---|---|---|
fit() 后再次滚动导致闪动 |
低 | 将滚动恢复整合到同一恢复函数中,减少多次跳转 |
| 输出写入与隐藏标签状态交织时覆盖用户历史位置 | 低 | 切换前冻结快照,重新激活后按快照恢复 |
| 阈值过大导致“已上翻少量行”也被当成贴底 | 低 | 使用保守的小阈值,仅认定底部附近少量行差 |
实施结果
Terminal.vue新增终端视口快照逻辑,使用buffer.active.viewportY与baseY判断当前是否处于底部附近。- 终端在失活时会冻结“视口行号 + 是否贴底”状态,重新激活时按该状态恢复,而不是无条件停在任意位置。
fit()和ResizeObserver路径都纳入了同一套恢复逻辑,避免尺寸重算后把视口意图覆盖掉。npm run build --workspace @nexus-terminal/frontend通过。- 受本地登录态与后端 SSH 会话现场限制,本轮未在浏览器里真实完成“多终端切换 + 输出滚动”交互验收。