- Add undoStack/redoStack refs with pushHistory/handleUndo/handleRedo
- Replace execCmd('undo')/execCmd('redo') with custom stack handlers
- Call pushHistory before structural changes (delete, insert field/table/image, formatting)
- Add onMouseDown preventDefault to toolbar and field library buttons to stop focus loss
- Implement saveSelection/restoreSelection using savedRangeRef
- Bind onBlur/onMouseUp/onKeyUp on editor to persist cursor position
- Restore selection in insertSmartField and insertImage before insertHTML
- Update experience record (#20)
42 lines
2.4 KiB
Markdown
42 lines
2.4 KiB
Markdown
# 需求分析 — TemplateManage 撤销/重做修复与插入字段光标定位(2026-04-17-12-51-47)
|
||
|
||
## 一、需求来源
|
||
|
||
用户反馈 TemplateManage 中存在两个严重的交互体验问题:
|
||
1. 删除智能字段(包括默认模板自带的和手动插入的)后,撤销/重做按钮完全失效。
|
||
2. 点击右侧字段库插入字段时,字段经常跳到下一行或错误位置。
|
||
|
||
## 二、具体需求拆解
|
||
|
||
### 需求 1:撤销/重做功能修复
|
||
|
||
**问题**:即使已经将删除逻辑改为 `execCommand('delete')`,撤销/重做按钮仍然无法恢复被删除的字段。
|
||
|
||
**原因**:浏览器原生的 `undo stack` 在 `contentEditable` 中结合 React 状态更新和强制 Range 操作时非常脆弱,容易被清空或打断。
|
||
|
||
**期望**:实现一个自定义的 undo/redo 历史栈,完全接管撤销/重做逻辑,确保任何内容变更(键盘输入、插入字段、删除字段)都能被正确撤销和恢复。
|
||
|
||
### 需求 2:插入字段光标定位修复
|
||
|
||
**问题**:点击右侧字段库按钮时,编辑器失去焦点(blur),浏览器内部光标位置丢失。再次 `focus()` 后,光标往往被重置到文档开头/末尾或新块级位置,导致 `insertHTML` 插入的字段跳到下一行。
|
||
|
||
**期望**:
|
||
- 点击字段库按钮时不让编辑器失去焦点。
|
||
- 若焦点仍丢失,则在插入前恢复上一次保存的光标位置(Range)。
|
||
- 插入的字段必须紧跟在插入前的光标位置,不强制换行。
|
||
|
||
## 三、影响范围分析
|
||
|
||
| 文件 | 改动说明 |
|
||
|------|----------|
|
||
| `src/pages/TemplateManage.tsx` | 新增 `undoStack` / `redoStack` refs;重写 `handleUndo` / `handleRedo`;替换 `execCmd('undo')` / `execCmd('redo')` 的调用;在关键操作(删除、插入)前增加 `pushHistory`;增加 `saveSelection` 和 `restoreSelection`;字段按钮增加 `onMouseDown={(e) => e.preventDefault()}` 阻止焦点流失。 |
|
||
|
||
## 四、验收标准
|
||
|
||
- [ ] 在模板中删除任意智能字段后,点击"撤销"按钮能立即恢复该字段。
|
||
- [ ] 撤销恢复后,点击"重做"按钮能再次删除该字段。
|
||
- [ ] 连续输入文字、插入字段、删除字段后,撤销/重做能按正确的历史顺序回退/前进。
|
||
- [ ] 在文字中间点击插入字段,字段紧跟光标位置,不跳到下一行或文档末尾。
|
||
- [ ] 多次在不同位置插入字段,每次都能准确定位。
|
||
- [ ] `npm run lint` 无编译错误。
|