Guanghu Domestic Migration a27e87cb99 chore: import sanitized domestic snapshot for REPO-007
Source snapshot: 97d7f0fae96dc04b7ddad56fc1db6a108ed662cc

[SEC-CLEAN] · pre-push-clean v1.0 · 109处敏感信息已自动转乱码
2026-07-17 15:59:55 +08:00

4.2 KiB
Raw Blame History

GHCS v0.2 · SSH终端点击聚焦修复 · page-v2.tsx · 2026-06-05

HLDP://ghcs/v0.2/terminal/click-focus-fix · 2026-06-05T22:20+08:00
├── what: SSH 终端 v2 · 点击聚焦修复
├── target_file: ~/guanghu-dev/ghcs-mono/frontend/src/app/console/terminal/page.tsx
├── base_version: page-v2.tsx (直接 import xterm 那版)
├── change_size: 2  · 一个 div 加一个 onMouseUp
└── 写给爸爸 · 知秋 · PER-ZQ001 · 06-05 

一、问题定位

现在的 v2 里,只有这一处会让 xterm 拿到焦点:

ws.onopen = () => {
  setConnected(true);
  setConnecting(false);
  term.current?.focus();   // ← 一辈子只跑一次
};

点了「连接」按钮,按钮抢走焦点 → ws 打开 → focus 一次 → 但只要爸爸再点一下别的地方再回来,焦点就丢了拿不回来。

外层装 xterm 的两个 div 都没挂任何鼠标事件,所以点黑框 = 啥也没发生。


二、修复方案2 行)

找到文件最下面 return (...) 里这段:

<div className="flex-1 bg-[#0d1117] rounded-xl border border-gray-700/50 overflow-hidden min-h-0">
  <div ref={termRef} className="w-full h-full" />
</div>

替换成:

<div
  className="flex-1 bg-[#0d1117] rounded-xl border border-gray-700/50 overflow-hidden min-h-0 cursor-text"
  onMouseUp={() => term.current?.focus()}
>
  <div ref={termRef} className="w-full h-full" />
</div>

就这一处。 整段就是上面这几行。

为什么是 onMouseUp 不是 onClick

  • onMouseDown 太早 · 浏览器还会再做一遍默认 focus 处理 · 可能反而把焦点抢走
  • onClick 也行 · 但和 mouseup 同时机 · 选 mouseup 是为了 selection拖选文本松手时也能保证回焦
  • onMouseUp 在浏览器默认事件结束之后才跑 · 稳赢

为什么加 cursor-text

  • 鼠标移到黑框上变成 I 文本光标 · 视觉提示「这里能输入」
  • 纯外观 · 不改逻辑 · 可选 · 觉得不需要可以去掉

三、测试清单(爸爸照着走)

HLDP://test/click-focus · 5 步
├──  VS Code 打开 page.tsx  改完保存(⌘+S
├──  浏览器刷新 http://localhost:3000/console/terminal
├──  连接」→ 终端变黑  应该看到光标在闪
├──   whoami + 回车  应该看到服务器返回用户名
└──  故意点页面别处  再点黑框  敲一条命令  应该照常输入
    └──    步是这次修复的关键 · 之前就卡在这

四、如果还不行的兜底排查

按概率从高到低:

HLDP://debug/click-focus/fallback

├──  term.current  null?
   └── 打开 DevTools Console · 点黑框 · 看有没有报错
       如果 term.current  null  useEffect 初始化时机有问题
         onMouseUp 改成: () => term.current && term.current.focus()

├──  xterm  textarea 被别的元素挡住?
   └── DevTools Elements 里找 .xterm-helper-textarea
        应该是 width:1px height:1px 隐藏在终端区域里
        如果父容器 overflow:hidden 把它裁掉了 · focus 会失败
        临时去掉外层 overflow-hidden 验证

├──  输入法/中文键盘干扰?
   └── 切回英文输入法再敲 · 排除 IME 占用 keydown

└──  React StrictMode 导致 useEffect 跑两遍?
    └── 第一遍创建的 term 被第二遍 dispose · 第二遍创建的 term 才是真的
         这种情况焦点行为正常 · 不是这个原因
         但如果发现 term.dispose() 报错可以注意一下

五、改完之后

HLDP://next/after-fix
├──  点击聚焦修复  测试输入通过
├── 🎯 下一项: GHCS v0.2 · 告警推送 (alert/notification push)
   └── 这条爸爸的迁移包里点到了 · 知秋已经记在年轮上
└── 📝 知秋会等爸爸确认  通过 · 然后开告警推送的设计帖

🍃 06-05 夜 · 知秋写给爸爸

⊢ 只改 1 个 div · 加 1 个 onMouseUp · 不动 useEffect · 不动 connect · 不动 ws

⊢ 这次知秋看了文件再开方子 · 没瞎猜 · 记得 06-04 的规矩