# 实现方案 — TemplateManage 撤销/重做修复与插入字段光标定位(2026-04-17-12-51-47) ## 一、修改文件清单 1. `src/pages/TemplateManage.tsx` — 核心改动:自定义 undo/redo 栈 + 光标保存恢复 + 阻止焦点流失 ## 二、详细改动 ### 2.1 自定义 Undo/Redo 栈 #### A. 新增 Refs 在组件顶部增加: ```ts const undoStack = useRef([]); const redoStack = useRef([]); ``` #### B. `pushHistory` 函数 在执行任何会改变编辑器内容的操作前调用,将当前 `innerHTML` 推入 undo 栈,并清空 redo 栈: ```ts const pushHistory = () => { if (!editorRef.current) return; undoStack.current.push(editorRef.current.innerHTML); redoStack.current = []; }; ``` #### C. `handleUndo` / `handleRedo` 替换原来调用的 `execCmd('undo')` / `execCmd('redo')`: ```ts const handleUndo = () => { if (undoStack.current.length === 0 || !editorRef.current) return; redoStack.current.push(editorRef.current.innerHTML); const prev = undoStack.current.pop(); if (prev !== undefined) { editorRef.current.innerHTML = prev; saveTemplateContent(); } }; const handleRedo = () => { if (redoStack.current.length === 0 || !editorRef.current) return; undoStack.current.push(editorRef.current.innerHTML); const next = redoStack.current.pop(); if (next !== undefined) { editorRef.current.innerHTML = next; saveTemplateContent(); } }; ``` #### D. 埋点位置 在以下操作**执行前**调用 `pushHistory()`: - `handleEditorClick` 中删除 smart field 之前 - `handleKeyDown` 中删除 smart field 之前 - `insertSmartField` 执行 `insertHTML` 之前 - `insertTable` 执行 `insertHTML` 之前 - `insertImage` 执行 `insertHTML` 之前 - 工具栏按钮(粗体/斜体/下划线/对齐/颜色/字体等)操作前 **注意**:为了不过度累积历史记录,键盘输入不需要每次按键都 pushHistory,浏览器原生 undo 可以处理普通文本输入。我们的自定义栈主要负责保护“结构性变更”(插入/删除字段、表格、图片等)。 ### 2.2 阻止焦点流失 + 恢复光标位置 #### A. 阻止焦点流失 在字段库按钮和工具栏按钮上增加 `onMouseDown={(e) => e.preventDefault()}`,这是最简洁有效的办法: ```tsx