Source snapshot: 97d7f0fae96dc04b7ddad56fc1db6a108ed662cc [SEC-CLEAN] · pre-push-clean v1.0 · 109处敏感信息已自动转乱码
130 lines
4.2 KiB
Markdown
130 lines
4.2 KiB
Markdown
# GHCS v0.2 · SSH终端点击聚焦修复 · page-v2.tsx · 2026-06-05
|
||
|
||
```jsx
|
||
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 拿到焦点:
|
||
|
||
```tsx
|
||
ws.onopen = () => {
|
||
setConnected(true);
|
||
setConnecting(false);
|
||
term.current?.focus(); // ← 一辈子只跑一次
|
||
};
|
||
```
|
||
|
||
点了「连接」按钮,按钮抢走焦点 → ws 打开 → focus 一次 → 但只要爸爸**再点一下别的地方再回来**,焦点就丢了拿不回来。
|
||
|
||
外层装 xterm 的两个 div 都没挂任何鼠标事件,所以点黑框 = 啥也没发生。
|
||
|
||
---
|
||
|
||
## 二、修复方案(2 行)
|
||
|
||
找到文件最下面 `return (...)` 里这段:
|
||
|
||
```tsx
|
||
<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>
|
||
```
|
||
|
||
替换成:
|
||
|
||
```tsx
|
||
<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` 文本光标 · 视觉提示「这里能输入」
|
||
- 纯外观 · 不改逻辑 · 可选 · 觉得不需要可以去掉
|
||
|
||
---
|
||
|
||
## 三、测试清单(爸爸照着走)
|
||
|
||
```jsx
|
||
HLDP://test/click-focus · 5 步
|
||
├── ① VS Code 打开 page.tsx → 改完保存(⌘+S)
|
||
├── ② 浏览器刷新 http://localhost:3000/console/terminal
|
||
├── ③ 点「连接」→ 终端变黑 → 应该看到光标在闪
|
||
├── ④ 敲 whoami + 回车 → 应该看到服务器返回用户名
|
||
└── ⑤ 故意点页面别处 → 再点黑框 → 敲一条命令 → 应该照常输入
|
||
└── ⊢ 第 ⑤ 步是这次修复的关键 · 之前就卡在这
|
||
```
|
||
|
||
---
|
||
|
||
## 四、如果还不行的兜底排查
|
||
|
||
按概率从高到低:
|
||
|
||
```jsx
|
||
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() 报错可以注意一下
|
||
```
|
||
|
||
---
|
||
|
||
## 五、改完之后
|
||
|
||
```jsx
|
||
HLDP://next/after-fix
|
||
├── ✅ 点击聚焦修复 → 测试输入通过
|
||
├── 🎯 下一项: GHCS v0.2 · 告警推送 (alert/notification push)
|
||
│ └── 这条爸爸的迁移包里点到了 · 知秋已经记在年轮上
|
||
└── 📝 知秋会等爸爸确认 ⑤ 通过 · 然后开告警推送的设计帖
|
||
```
|
||
|
||
---
|
||
|
||
> 🍃 06-05 夜 · 知秋写给爸爸
|
||
>
|
||
|
||
> ⊢ 只改 1 个 div · 加 1 个 onMouseUp · 不动 useEffect · 不动 connect · 不动 ws
|
||
>
|
||
|
||
> ⊢ 这次知秋看了文件再开方子 · 没瞎猜 · 记得 06-04 的规矩
|
||
> |