---
date: 2026-06-17
version: V1.4.2
tag: V1.4.2
commit: 2d212a62e152541eae18aff85ee8ec6184b1ce0f
author: William
license: MIT
---

V1.4.2 是一个**看似小、但非常影响手感**的修复版本——彻底解决「在输入框里快捷键失灵 / 切到画布后还要再点一下才能用」这两个高频反馈问题。

V1.0.0 起,设计器就提供了**完整的快捷键体系**:

| 类别 | 快捷键 | 行为 |
| --- | --- | --- |
| 工具切换 | `B` / `E` / `G` / `I` / `L` / `R` / `C` | 画笔 / 橡皮 / 填充 / 取色器 / 直线 / 矩形 / 圆形 |
| 历史 | `Ctrl+Z` / `Ctrl+Shift+Z` | 撤销 / 重做 |
| 文件 | `Ctrl+I` / `Ctrl+S` | 导入图片 / 保存到服务器 |

实际使用中,用户集中反馈了两个问题:

1. **在色板搜索框里按 `Ctrl+S`,浏览器居然把当前页面「另存为」到本地**——`Ctrl+S` 没被拦截。
2. **在搜索框里搜完颜色,鼠标点画布后,按 `C` 切到圆形工具没反应**,必须先点一下别处或敲一下回车才生效。

### Bug 1:`Ctrl+S` 在输入框里失灵

`App.tsx` 中 `handleKeyDown` 的旧实现:

```ts
// 旧代码(问题所在)
const handleKeyDown = useCallback((e: KeyboardEvent) => {
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return
// ……后续再处理 Ctrl+S / Ctrl+Z 等
})
```

> **整个回调在「检测到焦点在 input/textarea」时就 return 了**——包括 `Ctrl+S`、`Ctrl+Z` 这类**全局组合键**也被一并放弃,导致浏览器默认行为(保存网页)穿透。

### Bug 2:单字母快捷键在画布上不响应

当焦点停留在色板搜索框等 input 上时,**鼠标点画布并不能自动让 input 失焦**——`canvas / div` 默认不是 focusable,点自己不会主动 `blur` 当前焦点元素。

结果就是:用户以为「焦点已经在画布上了」,但**真实的 `document.activeElement` 仍然是搜索框**,单字母快捷键继续被当成「输入字符」处理。

### 修复 1:拆分 `Ctrl/Meta` 与单字母的判断顺序

`src/App.tsx` 重写 `handleKeyDown`:

```ts
// 新代码
const handleKeyDown = useCallback((e: KeyboardEvent) => {
const target = e.target as HTMLElement | null
const isInTextField =
target instanceof HTMLInputElement ||
target instanceof HTMLTextAreaElement ||
(target?.isContentEditable ?? false)

// ★ Ctrl/Meta + 组合键:必须放在「输入框检查」之前
// 原因:用户在色板搜索框等 input 中按 Ctrl+S 时,
// 浏览器会把当前页面存到本地。必须在 keydown 阶段
// preventDefault() 才能拦截。
if (e.ctrlKey || e.metaKey) {
if (e.key === 'z' && !e.shiftKey) { e.preventDefault(); undo(); return }
if (e.key === 'z' && e.shiftKey) { e.preventDefault(); redo(); return }
if (e.key === 'i' || e.key === 'I') { e.preventDefault(); openImport(); return }
if (e.key === 's' || e.key === 'S') { e.preventDefault(); openSave(); return }
return
}

// ★ 单字母工具键:仅在非输入框中响应
// (用户在搜索框敲 c 时应输入字符,而不是切工具)
if (isInTextField) return

const toolMap: Record<string, ToolType> = {
b: 'brush', e: 'eraser', g: 'fill',
i: 'picker', l: 'line', r: 'rect', c: 'circle',
}
// ……后续切换逻辑
})
```

**核心改动**:

- **Ctrl/Meta 组合键** → 无条件响应(在 keydown 阶段 `preventDefault()`,与是否在输入框无关)。
- **单字母工具键** → 仅在**非输入框**中响应(保持「搜索框敲 c 应输入 c」的预期)。
- 同时识别 `contentEditable` 元素(之前会漏判富文本编辑器场景)。

### 修复 2:点画布自动 blur 当前输入框

`src/components/Canvas/BeadCanvas.tsx` 的 `handleMouseDown` 开头新增:

```ts
const handleMouseDown = useCallback((e: React.MouseEvent) => {
e.preventDefault()

// ★ 让画布上的 mousedown 把焦点从色板搜索框等 input 上移开
// 这样用户切到画布后立刻按 C / B 等单字母快捷键即可生效
// (canvas/div 本身不是 focusable,点自己不会自动 blur 当前焦点)
const active = document.activeElement as HTMLElement | null
if (
active &&
(active.tagName === 'INPUT' ||
active.tagName === 'TEXTAREA' ||
active.isContentEditable) &&
typeof active.blur === 'function'
) {
active.blur()
}

// ……后续画布逻辑
})
```

**效果**:从色板搜索框搜完颜色 → 直接点画布 → 立刻按 `C` 切到圆形工具,**中间不需要再点别处**。

| 场景 | 旧版 | V1.4.2 |
| --- | --- | --- |
| 焦点在搜索框,按 `Ctrl+S` | 浏览器弹出「另存为」 | 弹「保存到服务器」对话框 |
| 焦点在搜索框,按 `Ctrl+Z` | 输入框撤销输入字符 | 全局撤销(撤销画布上一步操作) |
| 焦点在搜索框,按 `Ctrl+I` | 浏览器聚焦地址栏 | 弹「导入图片」对话框 |
| 搜索颜色后点画布,按 `C` | 无反应(焦点仍在 input) | 立即切到圆形工具 |
| 在搜索框敲 `c` | 输入字符 `c` ✅ | 输入字符 `c` ✅(未变) |

「快捷键」是设计器的**灵魂**——它决定了用户**画 100 颗拼豆要按多少次鼠标**。一次卡顿就是几十秒的等待,一个失灵就会让人放弃工具。V1.4.2 把这套交互彻底打磨到「**指哪打哪**」的水准。

- **改动文件**:`src/App.tsx`、`src/components/Canvas/BeadCanvas.tsx`。
- **零依赖新增**:纯浏览器原生 API(`preventDefault`、`document.activeElement`、`blur`)。
- **完全向后兼容**:默认行为对老用户**无任何感知变化**,只修复了原有问题。
- **性能影响**:可忽略(多了一次 `tagName` 比较 + 一次 `blur`)。

- **所有用户**建议升级:哪怕你很少用快捷键,也会在「不小心按到 Ctrl+S」时受益。
- **重度快捷键用户**(每天画几十张图纸):升级后手感**直接质变**。
- **零风险升级**:不涉及数据库结构变更,不影响已有图纸与作品。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。