闭包实现富文本编辑器撤销机制的核心是隔离状态、封装历史栈、控制操作边界;通过闭包保存undo/redo栈和currentcontent,返回savestate、undo、redo函数共享词法环境,仅在格式操作、延时input、blur、paste后调用savestate,并可选保存光标位置及限制栈大小防内存泄漏。

用闭包实现富文本编辑器的撤销机制,核心是**隔离状态、封装历史栈、控制操作边界**。不依赖外部状态管理库,靠闭包保存 undo/redo 栈和当前编辑位置,既安全又轻量。
用闭包封装撤销栈与当前状态
闭包能将 undoStack、redoStack 和 currentContent 封装为私有变量,避免被外部意外修改。返回的操作函数(如 saveState、undo、redo)共享同一词法环境:
function createUndoManager() {
const undoStack = [];
const redoStack = [];
let currentContent = '';
<p>// 保存当前编辑内容快照(如 innerHTML 或 selection + range)
function saveState(html) {
undoStack.push(html);
redoStack.length = 0; // 新操作清空重做栈
}</p><p>function undo() {
if (undoStack.length </p><p>function redo() {
if (redoStack.length === 0) return null;
const next = redoStack.pop();
undoStack.push(next);
return next;
}</p><p>return { saveState, undo, redo };
}</p>绑定到 contenteditable 元素并监听关键操作
不是每次按键都存——那样太频繁且冗余。只在语义明确的“编辑完成点”触发 saveState:
- 用户点击「加粗」「列表」等格式按钮后
-
input事件后延时 500ms(防连打),且内容确实变化了 - 焦点离开编辑区(
blur)时 - 粘贴(
paste)完成后(需用setTimeout确保 DOM 更新)
示例:监听格式按钮
const editor = document.getElementById('editor');
const undoMgr = createUndoManager();
<p>// 初始化时保存空白或默认内容
undoMgr.saveState(editor.innerHTML);</p><p>document.getElementById('bold-btn').addEventListener('click', () => {
document.execCommand('bold', false);
undoMgr.saveState(editor.innerHTML); // 仅在此处存
});</p>处理光标与选区还原(可选但实用)
纯存 innerHTML 会丢失光标位置。可在 saveState 中同时记录 getSelection() 信息:
- 用
selection.getRangeAt(0)获取 Range - 转成相对位置(如“第 n 个文本节点的第 m 个字符”),或用
range.cloneContents()+ 唯一标记定位 - 还原时用
range.selectNodeContents()或range.collapse()恢复焦点
简易做法(适合基础场景):保存前把光标包裹在带唯一 ID 的 <span data-undo-cursor></span> 中,还原后查找并 focus。
限制栈大小防内存泄漏
在 saveState 中加入长度限制,比如最多存 50 步:
function saveState(html) {
undoStack.push(html);
if (undoStack.length > 50) undoStack.shift(); // FIFO 弹出最老项
redoStack.length = 0;
}
这样既节省内存,又避免用户长时间编辑后卡顿。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











