如何让TinyMCE UndoManager忽略变更直到收到明确恢复通知?
TinyMCE异步场景下屏蔽Undo栈录入的实现方案
原生UndoManager.ignore()仅支持同步代码块,执行逻辑是进入方法时打上忽略标记,传入的同步回调执行完立刻移除标记,不会等待回调内部的异步任务执行完成,所以异步触发的内容变更无法被屏蔽。
可以通过以下两种变通方案实现你需要的开始/停止忽略能力:
方案1:扩展UndoManager实现可异步调用的忽略方法
通过临时替换UndoManager的快照添加逻辑,实现跨异步任务的变更拦截,逻辑和原生ignore保持一致,适配异步场景:
// 初始化编辑器后执行一次扩展即可 function patchUndoManager(editor) { const undoManager = editor.undoManager; let originAddHandler = null; undoManager.startIgnoring = () => { if (originAddHandler) return; // 暂存原生快照添加方法,替换为空函数拦截所有快照生成 originAddHandler = undoManager.add.bind(undoManager); undoManager.add = () => {}; // 屏蔽输入类自动快照 undoManager.typing = true; }; undoManager.stopIgnoring = () => { if (!originAddHandler) return; // 恢复原生逻辑 undoManager.add = originAddHandler; originAddHandler = null; undoManager.typing = false; // 追加当前状态快照,保证后续Undo/Redo逻辑连贯 undoManager.add(); }; }
调用方式完全匹配预期:
patchUndoManager(editor); editor.undoManager.startIgnoring(); doAsyncProcess(editor) .finally(() => { // 必须加finally兜底,避免异步报错导致Undo功能永久失效 editor.undoManager.stopIgnoring(); });
注意:异步执行期间建议给编辑器加loading遮罩或临时禁用编辑,否则这段时间内用户的手动操作也不会进入Undo栈。
方案2:手动裁剪异步期间生成的Undo快照
如果你的异步流程执行期间完全锁定编辑器,不存在用户操作介入,可以用更轻量的快照裁剪方案,不需要扩展原生方法:
// 记录异步开始前的Undo栈长度 const prevStackLength = editor.undoManager.data.length; doAsyncProcess(editor).then(() => { // 删除异步过程中自动生成的所有快照 editor.undoManager.data.splice( prevStackLength, editor.undoManager.data.length - prevStackLength ); // 修正Undo当前索引 editor.undoManager.index = prevStackLength - 1; // 追加处理完成后的内容快照 editor.undoManager.add(); });
这个方案的缺点是无法区分异步程序生成的快照和用户操作生成的快照,如果异步期间有用户操作,会被一起从Undo栈中移除,仅适合完全锁定编辑器的场景。
内容的提问来源于stack exchange,提问作者andysd
相关产品推荐
相关产品推荐

