当前位置:首页 > JavaScript

js 实现撤销重做

2026-03-15 22:54:53JavaScript

撤销重做的基本原理

撤销重做功能通常通过维护两个栈来实现:一个用于撤销(undoStack),一个用于重做(redoStack)。每次用户操作时,将当前状态保存到撤销栈中。执行撤销操作时,从撤销栈弹出状态并压入重做栈;执行重做操作时,从重做栈弹出状态并压入撤销栈。

实现步骤

定义状态管理类

创建一个类来管理状态和操作。初始化时设置空栈和当前状态。

class UndoRedoManager {
  constructor(initialState) {
    this.undoStack = [];
    this.redoStack = [];
    this.currentState = initialState;
  }
}

添加状态更新方法

当用户执行操作时,调用此方法将新状态保存到撤销栈中,并清空重做栈。

updateState(newState) {
  this.undoStack.push(this.currentState);
  this.currentState = newState;
  this.redoStack = [];
}

实现撤销功能

从撤销栈弹出最近的状态,保存到重做栈,并恢复为当前状态。

undo() {
  if (this.undoStack.length === 0) return false;
  this.redoStack.push(this.currentState);
  this.currentState = this.undoStack.pop();
  return true;
}

实现重做功能

从重做栈弹出最近的状态,保存到撤销栈,并恢复为当前状态。

redo() {
  if (this.redoStack.length === 0) return false;
  this.undoStack.push(this.currentState);
  this.currentState = this.redoStack.pop();
  return true;
}

完整代码示例

class UndoRedoManager {
  constructor(initialState) {
    this.undoStack = [];
    this.redoStack = [];
    this.currentState = initialState;
  }

  updateState(newState) {
    this.undoStack.push(this.currentState);
    this.currentState = newState;
    this.redoStack = [];
  }

  undo() {
    if (this.undoStack.length === 0) return false;
    this.redoStack.push(this.currentState);
    this.currentState = this.undoStack.pop();
    return true;
  }

  redo() {
    if (this.redoStack.length === 0) return false;
    this.undoStack.push(this.currentState);
    this.currentState = this.redoStack.pop();
    return true;
  }
}

使用示例

const manager = new UndoRedoManager({ text: '' });

manager.updateState({ text: 'Hello' });
console.log(manager.currentState); // { text: 'Hello' }

manager.updateState({ text: 'Hello World' });
console.log(manager.currentState); // { text: 'Hello World' }

manager.undo();
console.log(manager.currentState); // { text: 'Hello' }

manager.redo();
console.log(manager.currentState); // { text: 'Hello World' }

优化建议

对于大型应用或频繁状态更新的场景,可以考虑以下优化:

限制栈大小

防止内存无限增长,可以设置栈的最大长度。

constructor(initialState, maxStackSize = 100) {
  this.maxStackSize = maxStackSize;
  // ...其余初始化代码
}

updateState(newState) {
  if (this.undoStack.length >= this.maxStackSize) {
    this.undoStack.shift();
  }
  // ...其余代码
}

使用不可变数据

结合Immutable.js等库,可以更高效地管理状态变化和内存使用。

import { Map } from 'immutable';

const manager = new UndoRedoManager(Map({ text: '' }));
manager.updateState(Map({ text: 'Hello' }));

批量操作处理

对于连续操作,可以合并为单次撤销重做单元。

js 实现撤销重做

startBatch() {
  this.batch = [];
}

endBatch() {
  if (this.batch.length > 0) {
    this.undoStack.push(this.batch);
    this.redoStack = [];
  }
  this.batch = null;
}

updateStateInBatch(newState) {
  if (this.batch) {
    this.batch.push(this.currentState);
    this.currentState = newState;
  } else {
    this.updateState(newState);
  }
}

标签: 重做js
分享给朋友:

相关文章

js实现vue路由

js实现vue路由

Vue路由基础实现 使用Vue Router实现前端路由需要先安装并配置路由库。Vue Router是Vue.js官方的路由管理器。 安装Vue Router: npm install vue-r…

js 实现vue模板

js 实现vue模板

实现 Vue 模板的 JavaScript 方法 通过原生 JavaScript 可以实现类似 Vue 的模板渲染功能,主要包括数据绑定、指令处理和模板解析。以下是核心实现思路: 数据绑定与…

js实现预览

js实现预览

文件上传预览实现 使用JavaScript实现文件上传预览功能,可以通过FileReader对象读取文件内容并显示预览。以下代码支持图片、文本和PDF文件的预览: // HTML部分需要包含inpu…

js实现dh

js实现dh

JavaScript 实现 DH(Diffie-Hellman)密钥交换 Diffie-Hellman(DH)密钥交换是一种安全协议,允许双方在不安全的通信信道上建立一个共享密钥。以下是如何在 Jav…

js树实现

js树实现

树的基本概念 树是一种非线性的数据结构,由节点和边组成。每个节点包含一个值和指向子节点的引用。树的顶部节点称为根节点,没有子节点的节点称为叶节点。 树的实现方式 在JavaScript中,树可以通过…

js钟表实现

js钟表实现

实现JavaScript钟表的基本方法 创建一个简单的JavaScript钟表可以通过以下步骤完成,涵盖数字和模拟两种形式。 数字钟表实现 HTML结构只需一个显示时间的容器: <div i…