fix: custom undo/redo stack and cursor positioning in TemplateManage
- 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)
This commit is contained in:
29
工程分析/经验记录.md
29
工程分析/经验记录.md
@@ -494,6 +494,35 @@ if ((settings.autoInsertDelay || 0) > 0) {
|
||||
|
||||
---
|
||||
|
||||
## 记录 20:TemplateManage 自定义 Undo/Redo 与插入字段光标定位修复
|
||||
|
||||
**A. 具体问题**
|
||||
1. `TemplateManage` 中删除智能字段(通过红 × 或 Backspace/Delete)后,点击工具栏的"撤销"按钮无法恢复字段,"重做"也失效。
|
||||
2. 点击右侧字段库按钮插入字段时,字段经常跳到下一行或文档末尾。
|
||||
|
||||
**B. 产生问题原因**
|
||||
1. 即使将删除逻辑改为 `execCommand('delete')`,浏览器原生的 undo stack 在 `contentEditable` 中结合 React 状态更新时仍然非常脆弱,容易被清空。
|
||||
2. 点击侧边栏按钮会导致编辑器 `blur`,浏览器内部的光标位置(Selection/Range)丢失;再次 `focus()` 后光标被重置,导致 `insertHTML` 插入位置错误。
|
||||
|
||||
**C. 解决问题方案**
|
||||
1. **自定义 Undo/Redo 栈**:
|
||||
- 在 `TemplateManage.tsx` 中引入 `undoStack` 和 `redoStack` 两个 `useRef<string[]>([])`。
|
||||
- 实现 `pushHistory()`,在执行任何结构性变更(删除字段、插入字段、插入表格/图片、格式化命令)前将当前 `editorRef.current.innerHTML` 推入 undo 栈并清空 redo 栈。
|
||||
- 实现 `handleUndo()` / `handleRedo()`,直接替换工具栏按钮的 `execCmd('undo')` / `execCmd('redo')` 调用。从栈中取出历史 HTML 字符串并赋值给 `editorRef.current.innerHTML`,再调用 `saveTemplateContent()` 同步到 React state 和 `localStorage`。
|
||||
2. **阻止焦点流失**:
|
||||
- 在所有工具栏按钮和字段库插入按钮上增加 `onMouseDown={(e) => e.preventDefault()}`,阻止 mousedown 默认行为导致编辑器失去焦点。
|
||||
3. **光标位置记忆与恢复**:
|
||||
- 利用已有的 `savedRangeRef`,实现 `saveSelection()` 和 `restoreSelection()`。
|
||||
- 在编辑器 `<div>` 上绑定 `onBlur={saveSelection}`、`onMouseUp={saveSelection}`、`onKeyUp={saveSelection}`,持续记录光标位置。
|
||||
- 在 `insertSmartField` 和 `insertImage` 中,执行 `insertHTML` 前先调用 `restoreSelection()` 恢复光标,确保字段插入到正确的位置。
|
||||
|
||||
**D. 后续如何避免问题**
|
||||
- 对于 `contentEditable` 编辑器中的结构性变更(插入/删除特殊节点),如果原生 undo 不可靠,应尽早实现自定义历史栈(基于 HTML 字符串快照),完全接管撤销/重做逻辑。
|
||||
- 侧边栏/工具栏按钮与编辑器共存时,**必须**通过 `onMouseDown={e => e.preventDefault()}` 或等价手段阻止焦点流失,这是保证光标位置不丢失的最简单有效方案。
|
||||
- 插入操作前恢复 `savedRangeRef` 可以作为焦点流失后的兜底保险,两者结合使用效果最佳。
|
||||
|
||||
---
|
||||
|
||||
## 记录 14:智能字段插入间距修复与 Backspace 防误删
|
||||
|
||||
**A. 具体问题**
|
||||
|
||||
Reference in New Issue
Block a user