如何阻止Tiptap添加行时自动补全列,保留可变列表格结构?
如何阻止Tiptap表格自动补全行的列数以保持可变列结构
问题描述
我创建了一个列数可变的表格:
<table> <tbody> <tr> <th>Header</th> <th>Header</th> <th>Header</th> </tr> <tr> <td>one</td> </tr> <tr> <td>one</td> <td>two</td> </tr> <tr> <td>one</td> <td>two</td> <td>three</td> </tr> </tbody> </table>
使用addRowAfter方法添加新行时,Tiptap会自动插入额外的<td>元素以匹配表格的最大列数。例如在仅含一个<td>的行后添加新行,会生成如下结构:
<tr> <td></td> <td></td> <td>one</td> </tr>
如何阻止这种自动补全行为,保持表格的可变列结构?
当前使用的代码如下:
'use client' import { useEditor, EditorContent } from '@tiptap/react' import Table from '@tiptap/extension-table' import TableCell from '@tiptap/extension-table-cell' import TableHeader from '@tiptap/extension-table-header' import TableRow from '@tiptap/extension-table-row' import StarterKit from '@tiptap/starter-kit'; const Tiptap = () => { const editor = useEditor({ extensions: [ StarterKit, Table, TableCell, TableHeader, TableRow ], content: `<table> <tbody> <tr> <th>Header</th> <th>Header</th> <th>Header</th> </tr> <tr> <td>one</td> </tr> <tr> <td>one</td> <td >two</td> </tr> <tr> <td>one</td> <td>two</td> <td>three</td> </tr> </tbody> </table> `, }) const onClickTest = () => { editor.commands.addColumnAfter() } return <> <div style={{ margin: '10px' }}> <button style={{ background: 'grey', margin: '10px', color: 'white' }} onClick={onClickTest}>addColumnAfter</button> <EditorContent style={{ border: '1px solid black', margin: '10px' }} editor={editor} /> </div> </> } export default Tiptap
解决方案
要阻止Tiptap自动补全表格行的列数,需要修改Table扩展的默认行为,核心是重写添加行的逻辑,让新行只复制当前行的列数,而非匹配表格最大列数。
步骤1:自定义Table扩展
扩展原Table插件,重写addRowAfter命令的实现:
import Table from '@tiptap/extension-table'; const CustomTable = Table.extend({ addCommands() { return { ...this.parent?.(), addRowAfter: () => ({ tr, dispatch }) => { const { selection } = tr; // 定位当前选中的行节点 const row = selection.$anchor.node(-1).type.name === 'tableRow' ? selection.$anchor.node(-1) : selection.$anchor.parent; if (!row || row.type.name !== 'tableRow') return false; if (dispatch) { // 复制当前行的单元格数量,创建新行 const newRow = this.editor.schema.nodes.tableRow.createAndFill({}, row.children.map(cell => cell.type.createAndFill()) ); if (newRow) { const insertPos = selection.$anchor.end(-1) + 1; tr.insert(insertPos, newRow); } } return true; }, }; }, });
步骤2:替换原Table扩展
在编辑器配置中使用自定义的CustomTable替代原Table扩展:
const editor = useEditor({ extensions: [ StarterKit, CustomTable, // 替换为自定义扩展 TableCell, TableHeader, TableRow ], // ...其他原有配置 });
原理说明
Tiptap默认的addRowAfter命令会先计算整个表格的最大列数,再生成对应数量的单元格。通过重写该命令,我们改为复制当前选中行的单元格结构与数量,新行的列数将和当前行完全一致,不会自动补全到最大列数。
如果需要处理addRowBefore命令,用同样的方式在自定义扩展中重写该命令即可。
内容的提问来源于stack exchange,提问作者R1cer
相关产品推荐
相关产品推荐

