fix(TemplateManage): Ctrl+Z undo and smart-field insertion layout
- Intercept Ctrl+Z/Y keyboard shortcuts in keydown listener and route
to custom undoStack/redoStack to fix undo inconsistency.
- Replace execCommand('insertHTML') with precise Range.insertNode()
in insertSmartField to prevent <span> escaping out of <p> when
preceded by <br>.
This commit is contained in:
31
工程分析/经验记录.md
31
工程分析/经验记录.md
@@ -544,3 +544,34 @@ if ((settings.autoInsertDelay || 0) > 0) {
|
||||
- 在 `contentEditable` 中使用 `document.execCommand('insertHTML', ...)` 插入 HTML 时,**传入的字符串必须是无多余空白的紧凑单行**,否则浏览器会将其中的换行符解析为额外的文本节点,破坏排版和光标行为。
|
||||
- 对于 `contenteditable="false"` 的内联控件,若放置在块级边界(如 `<p>` 开头/结尾),务必增加键盘事件拦截,防止浏览器默认行为误删父级块。
|
||||
- 默认模板或任何通过代码生成的 HTML,应避免为了代码可读性而牺牲运行时 DOM 的纯净性;必要时在生成后对字符串进行 `.replace(/\s+/g, ' ').trim()` 处理。
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 记录 21:TemplateManage 快捷键 Undo/Redo 与字段插入排版修复
|
||||
|
||||
**A. 具体问题**
|
||||
1. TemplateManage 中删除 smart-field-wrapper 后按键盘 Ctrl+Z 无法撤销,但点击工具栏撤销按钮可以恢复。
|
||||
2. 当目标段落以 <br> 结尾时,从字段库插入 smart-field-wrapper 会被拆到下一行(<span> 跑到了 <p> 外部)。
|
||||
|
||||
**B. 问题产生原因**
|
||||
1. keydown 事件监听器只拦截了 Backspace/Delete,未拦截 Ctrl+Z/Ctrl+Y,导致浏览器原生 undo 与自定义 undoStack/
|
||||
edoStack 完全脱节。
|
||||
2. insertSmartField 使用 document.execCommand('insertHTML'),WebKit/Blink 在块级元素末尾存在 <br> 时,会自动将插入的 inline <span> 修正到块级元素外部,造成排版错位。
|
||||
|
||||
**C. 解决问题方法**
|
||||
1. **快捷键拦截**:在 keydown 监听的最开头增加 Ctrl+Z / Cmd+Z / Ctrl+Shift+Z / Ctrl+Y 的拦截,调用 e.preventDefault() 后路由到 handleUndo() 或 handleRedo()。
|
||||
2. **精确 Range 插入**:将 insertSmartField 的插入方式从 execCommand('insertHTML') 替换为手动 Range.insertNode():
|
||||
-
|
||||
estoreSelection() 恢复光标;
|
||||
-
|
||||
ange.deleteContents() 清空当前选区;
|
||||
- 将 HTML 字符串转为 DocumentFragment;
|
||||
-
|
||||
ange.insertNode(fragment) 精确插入到 Range 位置;
|
||||
- setStartAfter(lastNode) 把光标移动到插入内容末尾。
|
||||
|
||||
**D. 经验与教训总结**
|
||||
- 在 contentEditable 中实现自定义撤销栈时,必须**同时拦截界面按钮和键盘快捷键**的 undo/redo,否则两套历史机制会互相冲突。
|
||||
- document.execCommand('insertHTML') 对块级元素边界(尤其是 <br> 结尾)的自动修正行为不可控;需要精确插入时,应优先使用 Range.insertNode() 手动操作 DOM。
|
||||
- 任何对 contentEditable 的 DOM 修改后,都应同步保存内容(saveTemplateContent),确保 localStorage 中的模板数据与编辑器状态一致。
|
||||
|
||||
Reference in New Issue
Block a user