undoManager 源码分析

335 阅读3分钟

前言

当前端对某个DOM节点做了一系列操作之后,如果用户不想刷新去局部实现一步步回退操作,或者是回退之后在重新执行的话。 那么需要怎么做呢? 这就类似我们在写文档可以去执行撤销、重做的功能。那么节点是可以做到撤销重做的吗?

实现方式

想要实现对节点的撤销和回退,大概分为以下两种方式

  • 数据法

    什么是数据回退呢? 假如我对当前节点的字体做了一项操作, 当前fontSize 假如是12px, 第一步操作是将其改成14px,接着改成16px。那么撤销的步骤就是 先改成14px 再改成12px。 这就是对应刚刚对字体做操作的撤销事件。 那么数据法就是前端可以把当前节点的数据保存在一个数组里, 当对节点做的每一步操作 对应的数据都缓存起来, 那么撤销就相当于每次取数组对最后一项的数据然后去重新render 节点。 这个过程就是记录数据的变更记录从而一步步实现对节点的动态刷新

  • 事件法

    上述所说到数据法并不通用于所有场景。 如果是对单个节点实现撤销/重做的话。 数据法是可行的。但是如果是对于比较复杂的多节点的话。存储多节点的数据的话, 数据的量非常庞大。不利于维护。 那么这时候就可以用到事件法。那么什么是事件法呢?接下来我们来通过解析undoManager的源码来阐述事件法如何去实现撤销/重做

源码解析

www.npmjs.com/package/und… 源码地址

通过源码地址, 我们可以来梳理一下源码

undoManager 方法

undoManager 主要暴露出有这些方法

  • add (往历史堆栈中添加一个 undo、redo历史)
  • undo (执行历史堆栈中最后一个 undo 执行函数)
  • redo(执行历史堆栈中最后一个 redo 执行函数)
  • clear(将历史堆栈全部清空且不会执行他们)
  • setLimit(设置历史堆栈的最大数量,若当前历史堆栈已满则会淘汰最早进入的数据)
  • hasUndo(判断当前历史堆栈中是否有可执行的 undo)
  • hasRedo(判断当前历史堆栈中是否有可执行的 redo)
  • setCallback(设置回调,当添加或者执行undo、redo 会触发的回调)
  • getIndex(获取当前历史堆栈所在的下标)
  • getCommands(获取当前历史堆栈数据)

方法解析

  • add image.png

  • undo image.png

  • redo

image.png

redo 方法的话和undo 基本是一样的 只是当前的下标不同 redo 相当于重做 所以下标需要 +1

  • hasUndo
  • hasRedo
  • getcommands
  • getIndex

image.png

总结

undoManager 也是利用了数组来存储需要执行的撤销和重做事件。并且源码上返回的事件或者是下标 都是基于数组去操作 并且复杂度不高,性能上可行。所以利用undoManager 去做撤销/重做 不失为一种方式 让我们只需要去关注事件本身即可