Draft JS从外部脚本更新EditorState如何保留撤销/重做栈
问题根因
你当前的实现丢失撤销/重做栈的核心原因是使用了EditorState.createWithContent创建全新的编辑器状态,该方法会完全丢弃原有编辑器实例的历史栈数据。
解决方案
要保留历史栈需要使用DraftJS内置的Modifier API处理内容修改,再通过EditorState.push提交变更,DraftJS会自动将本次修改记录到历史栈中,完整实现代码如下:
import { Modifier, EditorState, BlockMapBuilder } from 'draft-js'; function appendBlocksFromHtml(editorState, htmlString) { const newBlockData = htmlToDraft(htmlString); const currentContent = editorState.getCurrentContent(); // 合并新旧实体映射,避免插入带实体的内容(链接、图片等)时报错 const mergedEntityMap = { ...currentContent.getEntityMap(), ...newBlockData.entityMap }; const contentWithMergedEntities = currentContent.set('entityMap', mergedEntityMap); // 构建要插入的块片段 const fragment = BlockMapBuilder.createFromArray(newBlockData.contentBlocks); // 获取文档末尾的选中状态 const selectionAtEnd = contentWithMergedEntities.getSelectionAfter(); // 用Modifier API插入片段,生成新的内容状态 const newContent = Modifier.insertFragment( contentWithMergedEntities, selectionAtEnd, fragment ); // 用EditorState.push提交修改,会自动保留历史栈 const newEditorState = EditorState.push( editorState, newContent, 'insert-fragment' ); // 移动光标到末尾 return EditorState.moveSelectionToEnd(newEditorState); }
注意事项
EditorState.push的第三个参数'insert-fragment'为修改类型标记,DraftJS会根据该类型自动处理历史栈的合并逻辑,你也可以根据自身业务场景自定义修改类型。- 如果需要将内容插入到指定位置而非文档末尾,仅需将
selectionAtEnd替换为对应位置的SelectionState实例即可。 - 直接手动拼接块数组的方式会跳过DraftJS的内部内容校验逻辑,使用官方
ModifierAPI可以避免出现块结构、实体关联异常的问题。
内容的提问来源于stack exchange,提问作者Shubhanu Sharma
相关产品推荐
相关产品推荐

