JavaScript 实现支持撤销和重做的状态管理器要实现一个支持撤销和重做功能的状态管理器,核心思路是维护历史快照数组和当前指针,通过记录每次状态变化来实现操作回退。以下是完整的实现方案:
核心实现原理
- 历史快照数组:存储所有状态变更记录
- 当前指针:指示当前所处的历史位置
- 最大步数限制:防止内存溢出(可选)
完整实现代码
class UndoRedoManager { constructor(maxSteps = 50) { this.history = []; // 存储所有状态快照 this.currentIndex = -1; // 当前状态指针 this.maxSteps = maxSteps; // 最大历史记录数 } // 设置新状态 setState(newState) { // 截断当前指针之后的历史(防止重做后操作产生分支) this.history = this.history.slice(0, this.currentIndex + 1); // 深拷贝新状态并存储 this.history.push(this.deepCopy(newState)); // 移动指针到最新位置 this.currentIndex++; // 超出最大步数时删除最旧记录 if (this.history.length > this.maxSteps) { this.history.shift(); this.currentIndex--; } } // 撤销操作 undo() { if (this.canUndo()) { this.currentIndex--; return this.deepCopy(this.history[this.currentIndex]); } return null; } // 重做操作 redo() { if (this.canRedo()) { this.currentIndex++; return this.deepCopy(this.history[this.currentIndex]); } return null; } // 检查是否可撤销 canUndo() { return this.currentIndex > 0; } // 检查是否可重做 canRedo() { return this.currentIndex <绝扒 this.history.length - 1; } // 获取当前状态 getCurrentState() { if (this.currentIndex === -1) return null; return this.deepCopy(this.history[this.currentIndex]); } // 深拷贝方法(处理纯数据对象) deepCopy(obj) { return JSON.parse(JSON.stringify(obj)); } // 清空历史记录 clear() { this.history = []; this.currentIndex = -1; }}关键方法说明
setState(newState):
截断指针后的历史记录
存储新状态的深拷贝
更新指针位置
处理最大步数限制
undo():
检查是否可撤销
指针前移并返回前一个状态友核
redo():
检查是否可重做
指针后移并返回后一个状态
deepCopy(obj):
使用JSON方法实现简单深拷贝
适用于纯数据对象(不含函数、循环引用等)
使用并告昌示例
// 创建管理器(最多保留10步历史)const manager = new UndoRedoManager(10);// 记录状态变更manager.setState({ text: "Hello" });manager.setState({ text: "Hello World" });manager.setState({ text: "Hello Everyone" });// 撤销操作console.log(manager.undo()); // { text: "Hello World" }console.log(manager.undo()); // { text: "Hello" }// 重做操作console.log(manager.redo()); // { text: "Hello World" }// 获取当前状态console.log(manager.getCurrentState());优化建议
差量存储:
对于大型状态对象,可考虑只存储变更部分而非完整快照
示例实现:{ type: 'update', path: ['text'], value: 'new text' }
状态变化监听:
结合事件机制或观察者模式自动触发UI更新
示例:class ObservableUndoRedoManager extends UndoRedoManager { constructor(maxSteps) { super(maxSteps); this.listeners = []; } setState(newState) { super.setState(newState); this.notify(); } subscribe(callback) { this.listeners.push(callback); } notify() { this.listeners.forEach(cb => cb(this.getCurrentState())); }}
智能历史记录:
在setState前比较前后状态,避免存储无意义变更
示例实现:setState(newState) { const current = this.getCurrentState(); if (JSON.stringify(current) !== JSON.stringify(newState)) { // 只有状态实际变化时才存储 super.setState(newState); }}
更健壮的深拷贝:
对于包含函数、Symbol或循环引用的对象,可使用专用库如lodash.cloneDeep
示例:import cloneDeep from 'lodash.cloneDeep';// 替换deepCopy方法deepCopy(obj) { return cloneDeep(obj);}
适用场景
这种状态管理器特别适合:
- 文本编辑器
- 图形绘制应用
- 复杂表单
- 配置管理工具
- 任何需要操作回退功能的交互式应用
实现简单但功能完整,可根据具体需求进行扩展和优化。