大家通常先找一个 Fabric.js 撤销重做库,然后才发现还需要保存、id 和冲突检查。这篇文章对比几种常见方案。版本号于 2026 年 9 月在 npm 上核对。
一览
手写 toJSON | fabric-history 2.0 | fabricjs-react 2.2 | 这个包 | |
|---|---|---|---|---|
| Fabric.js 版本 | 任意 | 5 | 5 和 6 | 6 和 7 |
| 撤销和重做 | 自己写 | 有 | 没有 | 有 |
| 撤销怎么存 | — | 每一步存整个画布的 JSON | — | 只存变化的对象 |
| 稳定的对象 id | 没有 | 没有 | 没有 | 有 |
| 用存储保存和加载 | 自己写 | 没有 | 没有 | 有 |
| 自动保存和冲突检查 | 没有 | 没有 | 没有 | 有 |
| 保留自定义属性 | 每次调用都要列出 | 在画布上列出 | — | 注册一次 |
| 崩溃恢复 | 没有 | 没有 | 没有 | 有 |
| React hooks | — | — | 有 | 有,可选 |
手写 toJSON 和 loadFromJSON
Fabric.js 本身就能把画布转成 JSON 再转回来。做演示时这就够了。真正给用户用时,工作才开始:稳定的 id、加载失败的图片、互相抢的加载、乱序到达的保存,还有撤销。为什么需要文档引擎一文逐条列出了这些问题。
fabric-history
fabric-history 是一个小巧的 Fabric.js 撤销重做库。导入一次后,它通过修改 Canvas.prototype,给每个画布加上 canvas.undo() 和 canvas.redo()。每一步都把整个画布存成 JSON 字符串,做法简单,但图一大就会变慢、占内存。2.0 版依赖 Fabric.js 5,也不负责保存、加载或分配 id。
如果你只要在一个小的 Fabric.js 5 画布上撤销,可以选它。
fabricjs-react
fabricjs-react 给 React 提供了一个画布组件和一个用来拿到 Fabric.js 编辑器的 hook。它帮你在 React 里挂载画布,但不保存文档,也不记录历史,所以可以和这个包一起用。
这个包
当用户会在你的编辑器里保存作品时,就选这个包。撤销只存变化的部分,对象有几千个时每一步也很快。保存同一时间只跑一次,并带修订号检查,崩溃后未保存的内容也不会丢。它需要 Fabric.js 6 或 7。
如果你只要撤销、从不保存,一个更小的 Fabric.js 撤销重做库可能就够了。如果要保存,可以对照上线清单,看看自己要写多少东西。