富文本编辑器中如何正确插入并编辑表格?
我用 React + Draft.js 做富文本编辑器,现在想支持表格功能。但插入表格后,光标无法正常进入单元格,也不能用方向键在单元格间移动,感觉像是没被识别为可编辑区域。
我试过用原生 contentEditable 的 div 模拟,但和 Draft.js 的 EditorState 冲突了。下面是我目前插入表格的代码:
const insertTable = () => {
const table = '<table><tr><td></td><td></td></tr></table>';
const contentState = Modifier.replaceText(
editorState.getCurrentContent(),
editorState.getSelection(),
table,
null
);
setEditorState(EditorState.push(editorState, contentState, 'insert-table'));
};
这样插入的表格完全不能交互,有啥靠谱的方案吗?是不是得用自定义 block render?
首先,我们需要把表格当作一个自定义的 block 来处理,而不是简单地插入 HTML 字符串。这样做有几个好处:一是可以更好地控制编辑行为,二是能和 Draft.js 的状态管理机制更好集成。
这里是一个可行的方案:
这里需要注意几个关键点:
1. 我们用了 convertFromHTML 来解析 HTML 表格为 ContentBlock,这比直接插入字符串要靠谱得多。
2. 使用 splitBlock 和 insertBlock 来正确处理插入逻辑,避免破坏现有的 ContentState 结构。
为了让表格内容可编辑,我们还需要给 Draft.js 提供一个自定义的 block render 组件:
这段代码的核心思想是:让 Draft.js 认识到这是一个特殊的 block,并且用我们指定的方式来渲染它。这样就能解决光标无法进入单元格的问题了。
最后提醒一句:Draft.js 的表格支持不是开箱即用的功能,可能需要根据具体需求做一些定制化开发。但上面这个方案应该能帮你解决大部分问题。如果遇到其他特殊情况,欢迎继续讨论。
Modifier.replaceText插入 HTML 字符串,它只会当成纯文本处理,不会解析成真正的 DOM 结构,更别谈交互了。核心问题在于:Draft.js 的 block 是独立的编辑单元,你想在 block 内部再搞出可编辑的单元格,必须用自定义 block render。
标准做法是这样的:
1. 先定义一个自定义 block type,比如叫
table2. 用
blockRendererFn捕获这个 block,返回一个自定义组件3. 表格组件内部用原生 contentEditable 实现编辑
几个关键点:
- 表格 block 的
editable要设为false,否则 Draft.js 会尝试把它当成普通文本编辑,导致行为混乱- 表格内部用独立的 contentEditable div,每个单元格独立处理
- 数据通过
onChange回写到 Draft.js 的 block data 中,保持状态同步- 方向键问题需要在表格组件的 keyDown 处理里自己实现,或者用键盘事件冒泡
如果你还需要在表格里支持更复杂的操作(比如合并单元格),原理是一样的,数据结构设计好就行。