GrapesJS UndoManager 模块 API 完全指南:撤销/重做堆栈管理实战

发布时间:2026/9/12 1:04:23

GrapesJS UndoManager 模块 API 完全指南:撤销/重做堆栈管理实战 GrapesJS UndoManager 模块 API 完全指南撤销/重做堆栈管理实战【免费下载链接】grapesjsFree and Open source Web Builder Framework. Next generation tool for building templates without coding项目地址: https://gitcode.com/GitHub_Trending/gr/grapesjsGrapesJS 的 UndoManager 模块负责管理画布Canvas中一系列更改操作的历史堆栈为组件增删改、CSS 规则调整等提供撤销Undo与重做Redo能力。本文以 docs/api/undo_manager.md 中定义的 API 为骨架结合 模块源码、配置定义 与 单元测试系统讲解该模块的配置参数、全部公开方法及底层跟踪机制读完即可在自己的插件或项目中熟练控制撤销/重做流程。模块概览与实例获取UndoManager 是 GrapesJS 编辑器内置的核心模块它基于backbone-undo库对画布内的 Model / Collection 变更进行追踪并将变更记录到堆栈中。编辑器实例化后通过以下方式获取模块句柄const um editor.UndoManager;从源码看该模块继承自Module基类在 编辑器模型 中以get UndoManager()的形式对外暴露um即 UndoManagerModule 的实例。它默认处于启用状态传入undoManager: false时模块被标记为禁用堆栈长度会被置为 0见 index.ts#L53-L55所有跟踪行为随之失效。配置参数编辑器级配置入口在初始化编辑器时通过undoManager配置项传入配置对象或布尔值见 editor/config/config.ts#L305-L308const editor grapesjs.init({ container: #gjs, undoManager: { maximumStackLength: 500, trackSelection: true, }, });默认值为空对象{}见 editor/config/config.ts#L494即全部使用内置默认值。支持的配置项根据 undo_manager/config.ts 的类型定义配置项如下配置项类型默认值说明maximumStackLengthnumber500撤销堆栈最多保存的操作项数量超过后最旧的操作会被丢弃trackSelectionbooleantrue是否跟踪组件选择selection变化使其也可被撤销/重做其中trackSelection的实现体现在 index.ts#L155-L158模块加载完成后postLoad若配置开启且模块未禁用会自动把em.get(selected)集合注册到跟踪器中对应测试用例见 undo_manager 测试中的 Selection tracking 小节。完整禁用 UndoManager将undoManager设为false即可完全关闭撤销功能const editor grapesjs.init({ container: #gjs, undoManager: false, });此时um.isDisabled为trueadd、remove、removeAll等方法直接短路返回见 index.ts#L175-L204hasUndo()恒为false、堆栈保持为空。这一行为在测试Disabled undo manager does not track changes中有明确验证test/specs/undo_manager/index.ts#L28-L42。核心 API 详解以下方法均通过editor.UndoManager实例调用除特别说明外返回this因此支持链式调用。getConfig()获取当前模块的配置对象包含默认值合并结果const config um.getConfig(); console.log(config.maximumStackLength); // 500实体跟踪管理add(entity)将一个实体Backbone Model 或 Collection注册到跟踪器中此后该实体及其包含的变更会被记录um.add(someModelOrCollection);注意新建的组件Components和 CSS 规则CSSRules会被自动加入跟踪无需手动调用add见 index.ts#L168-L179 的注释说明。这一点在测试中得到了印证——测试直接对wrapper追加组件、对editor.Css添加规则后um.hasUndo()立即为truetest/specs/undo_manager/index.ts#L45-L57、#L138-L152。remove(entity)移除并停止跟踪指定实体um.remove(someModelOrCollection);removeAll()移除全部已注册实体um.removeAll();isRegistered(obj)返回布尔值用于判断实体当前是否处于跟踪状态um.isRegistered(someModelOrCollection); // true | false其底层通过this.getInstance().objectRegistry.isRegistered(obj)实现index.ts#L300-L302。跟踪开关start()开始/恢复跟踪变更stop()停止跟踪变更。两者通常成对使用例如在执行大量一次性初始化操作时临时关闭跟踪um.stop(); // 此处产生的变更不会被记录 um.start();底层分别对应backbone-undo的startTracking()与stopTracking()index.ts#L212-L225。撤销与重做undo()撤销最近一次变更redo()重做最近一次被撤销的变更。二者均接受一个可选布尔参数all默认值为true表示一次调用是否应一次性回退/重放全部堆栈项um.undo(); // 撤销最近一次或全部操作 um.redo(); // 重做最近一次或全部操作 um.undo(false); // 仅回退一步 um.redo(false); // 仅前进一步值得注意的是源码在调用底层方法前会检查!em.isEditing()index.ts#L234-L238、#L257-L261即当富文本/内联编辑器处于编辑状态时不会执行撤销/重做以避免干扰正在进行的文本编辑。undoAll()与redoAll()则分别撤销/重做全部变更不带步数控制um.undoAll(); um.redoAll();状态查询hasUndo()判断堆栈中是否存在可撤销的操作hasRedo()判断是否存在可重做的操作if (um.hasUndo()) um.undo(); if (um.hasRedo()) um.redo();底层调用isAvailable(undo)/isAvailable(redo)index.ts#L280-L292。测试中的初始状态断言为新建编辑器、清空堆栈后二者均为false且堆栈长度为 0test/specs/undo_manager/index.ts#L22-L26。堆栈访问getStack()返回当前更改堆栈。官方文档描述返回类型为Collection实际实现直接返回底层backbone-undo的this.um.stackindex.ts#L311-L313可以按集合方式遍历const stack um.getStack(); stack.each((item) { // 处理每条历史记录 });如需将一次批量操作如一次 append 多个组件视为单个撤销动作可使用源码中的getStackGroup()私有方法——它依据magicFusionIndex对相邻操作分组返回去重后的列表index.ts#L326-L339。测试Grouped component additions are treated as one undo action验证了该行为一次wrapper.append(div1/divdiv2/div)后getStackGroup()长度为 1且单次um.undo()即可移除两个组件test/specs/undo_manager/index.ts#L127-L135。skip()临时关闭跟踪skip(clb)在回调执行期间临时停止跟踪回调结束后恢复原有跟踪状态um.skip(() { // 此处的变更不会被记录到撤销堆栈 component.set(content, new value); });源码实现会先判断当前是否处于跟踪状态若正在跟踪则先stop()执行回调后再start()index.ts#L349-L355。编辑器层面的 editor.skip() 同样委托给um.skip()用于执行操作但不触发存储与撤销的场景。clear()清空堆栈clear()清空全部历史记录常用于开始一段新操作前重置状态um.clear();返回this。模块销毁时destroy()也会执行this.clear().removeAll()index.ts#L420-L422。底层跟踪机制与调用链基于 backbone-undo 的类型化跟踪模块在构造函数中创建底层UndoManager实例track: true, register: []并通过changeUndoType注册了四种变更类型index.ts#L57-L143change模型属性变化。通过condition判断实体是否带有_undo标记布尔值或属性名数组支持_undoexc排除属性on回调比较previousAttributes()与toJSON({ fromUndo: true })生成{ object, before, after }记录。add向已注册集合添加模型记录{ object: collection, after: model }。remove从已注册集合移除模型记录{ object: collection, before: model }。reset集合重置记录前后完整模型列表并提供对应的undo/redo回调执行collection.reset。同时hasSkip(opts)检测到avoidStore、noUndo、partial任一选项时跳过记录index.ts#L40。这意味着在业务代码中任何set/append操作都可以通过{ noUndo: true }选项明确排除在撤销历史之外comp.set(content, no undo content, { noUndo: true });对应测试Skipping undo for component modification验证了该行为——带noUndo的修改不会被um.undo()回退test/specs/undo_manager/index.ts#L285-L301。事件联动模块监听底层undo/redo事件触发已选中组件的rerender:layer重渲染index.ts#L145-L147并将事件转发为编辑器级事件。对应的事件枚举定义在 editor/types.ts#L138-L149editor.on(undo, () { console.log(Undo executed); }); editor.on(redo, () { console.log(Redo executed); });完整实战示例下面是一个覆盖跟踪—操作—撤销/重做—跳过全流程的示例const editor grapesjs.init({ container: #gjs, undoManager: { maximumStackLength: 500, trackSelection: true, }, }); const um editor.UndoManager; // 1. 初始状态无撤销、无重做、堆栈为空 console.log(um.hasUndo(), um.hasRedo(), um.getStack().length); // false false 0 // 2. 添加组件新组件自动被跟踪 const wrapper editor.getWrapper(); wrapper.append(div classboxHello/div); console.log(um.hasUndo()); // true // 3. 撤销/重做 um.undo(); // 组件被移除 um.redo(); // 组件重新出现 // 4. 临时跳过跟踪批量导入时不产生历史记录 um.skip(() { wrapper.append(spanA/spanspanB/span); }); console.log(um.hasUndo()); // falseskip 内的操作未入栈 // 5. 指定 noUndo 排除单个操作 wrapper.append(pundoable/p); wrapper.components().at(0).set(content, x, { noUndo: true }); // 6. 清空历史开启新一轮操作 um.clear();注意事项与限制自动跟踪范围新增的组件与 CSS 规则会自动注册但并非所有模块如 Asset Manager、设备切换、面板可见性都默认接入撤销系统。测试文件中以describe.skip标记的Asset Manager changes与Editor states changes小节test/specs/undo_manager/index.ts#L187-L261表明这些场景的撤销支持尚在规划中不应假设其行为可用。编辑态保护富文本编辑过程中调用undo()/redo()会被!em.isEditing()守卫拦截编辑完成后才能正常撤销/重做。堆栈上限maximumStackLength默认 500超限后最早记录会被挤出长期运行的高频操作编辑器建议评估该上限是否满足需求。skip()与noUndo是两套独立机制skip()从源头停止跟踪适合批量导入noUndo/avoidStore/partial选项则作用于单次操作适合精确排除个别变更。禁用后的行为undoManager: false时模块整体失效add、remove、removeAll、start、stop、undo系列及clear均返回this但不产生任何效果。如需查阅更多编辑器 API可参考 docs/api/editor.mdUndoManager 模块的完整实现位于 packages/core/src/undo_manager/index.ts配置定义见 packages/core/src/undo_manager/config.ts全部行为均有对应的 单元测试 可作参照。【免费下载链接】grapesjsFree and Open source Web Builder Framework. Next generation tool for building templates without coding项目地址: https://gitcode.com/GitHub_Trending/gr/grapesjs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/12 1:04:23

供应链数字化转型:从预测到物流的智能升级

1. 供应链管理概述:从传统到数字化的演进供应链管理(Supply Chain Management, SCM)这个领域最早可以追溯到20世纪80年代,当时企业开始意识到单纯优化内部生产流程已经不够,需要把视野扩展到整个供需网络。我2008年刚入…

2026/9/12 1:59:29

Spring框架进阶:核心原理与生产实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/12 1:59:29

PyTorch语音情感识别实战:MFCC特征对齐与Bi-LSTM建模

简介:本资源是一份面向高校计算机、人工智能方向学生的课程设计实践项目,聚焦语音情感识别这一典型多模态AI任务,提供基于PyTorch的完整端到端实现方案。项目覆盖音频预处理(MFCC特征提取)、Bi-LSTM模型构建、训练/评估…

2026/9/12 1:59:29

贝叶斯优化加速LSTM超参调优:时序预测实战指南

简介:本资源是一份面向MATLAB初学者与时间序列建模进阶学习者的完整实践方案,聚焦贝叶斯优化与LSTM协同建模这一前沿技术组合,解决金融、电力、气象等场景中高精度时序预测难题。压缩包共5个文件(2个txt说明文档、2个核心m脚本、1…

2026/9/12 1:54:29

上海区县乡镇村SHP点位数据处理:坐标系校验与批量转换实战

简介:上海市县区乡镇村各级点位Shapefile数据包,专注于提供全市范围内区县、乡镇、村三级行政单位位置点信息,适用于GIS空间分析、区域对比、专题制图及智慧城市相关研究。面向地理信息开发人员、数据分析师及城市规划研究者,可快…

2026/9/10 16:39:38

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/10 11:16:38

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/9 16:31:09

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/12 0:04:17

MATLAB仿生优化框架:长鼻浣熊算法多策略融合实现

简介:本资源是一份面向智能优化算法研究者与MATLAB初学者的仿生智能算法实践代码包,聚焦于长鼻浣熊优化算法(COA)的多策略改进与性能验证。针对传统COA易陷局部最优、收敛精度不足等问题,作者融合Circle映射初始化提升…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 JavaWeb 的校园一卡通管理系统的设计与实现 基于 JavaWeb 的校园卡业务管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 Java 的图书馆借阅管理平台的搭建与实现 基于 Java 的图书馆综合管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/10 12:32:02

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/10 15:19:50

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/10 15:49:53

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码