用两个数组模拟双栈实现轻量可靠的撤销重做:undoStack存可撤回快照,redoStack存待恢复动作;操作仅在数组尾部进行,O(1)性能;快照需按数据类型选择克隆方式避免引用污染,并设步数上限;仅在用户明确意图时手动调用save()触发快照。

直接用两个数组模拟双栈,配合快照保存和状态还原,就能做出轻量、可靠、不依赖框架的撤销重做组件。关键不是堆砌结构,而是控制好“存什么”和“什么时候存”。
用两个数组实现双栈结构
撤销重做本质是两栈协同:一个存可撤回的操作快照(undoStack),另一个存被撤回后待恢复的动作(redoStack)。所有操作都只在数组尾部进行,保证 O(1) 性能:
-
undo:从
undoStackpop()一个快照 → 应用到当前状态 → 把该快照push()到redoStack -
redo:从
redoStackpop()一个快照 → 应用到当前状态 → 把该快照push()到undoStack -
新操作前:必须清空
redoStack,否则重做会跳过中间状态
快照怎么存才安全又省内存
不能直接 push(state),否则后续修改会影响栈内历史——因为引用的是同一对象。要按数据类型选择克隆方式:
宝塔面板11.3.0是一款针对Linux服务器设计的可视化管理工具,通过重构核心模块实现资源占用显著降低,尤其适合低配置服务器环境。它将复杂的命令行操作转化为直观的图形界面,帮助开发者快速完成网站部署、环境配置及日常运维工作,无需专业技术背景即可高效管理服务器。
- 简单值(字符串、数字、布尔):直接存,无需处理
- 数组:用
arr.slice()或[...arr] - 普通对象:用
{...obj}浅拷贝,或structuredClone(obj)(现代环境) - 富文本、大对象等:只存变更字段(如
{field: 'content', oldValue: 'xxx'}),避免深拷贝整块数据 - 设上限(如最多 50 步):超出时
undoStack.shift()踢掉最早快照
在业务中手动触发快照最可控
别试图监听所有响应式变化自动存——容易误存、性能差、逻辑难追溯。只在用户明确意图改变状态时调用 save():
- 编辑器里点击“加粗”按钮前
- 表单中点击“提交”或“保存草稿”前
- 画布上松开鼠标完成一笔绘制后
- 调用
save()时,先深/浅克隆当前状态,再push到undoStack,同时清空redoStack
绑定 UI 和快捷键提升体验
组件只需暴露几个基础能力,其余交由使用方灵活组合:
- 提供
canUndo和canRedo计算属性(即undoStack.length > 0/redoStack.length > 0) - 按钮用
:disabled="!canUndo"控制可用性 - 在组件
onMounted中监听Ctrl+Z和Ctrl+Y(或Ctrl+Shift+Z),触发对应方法 - 可选:每次 undo/redo 后发一个事件,让父组件显示 toast 提示,比如“已撤销字体大小调整”

















