You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 23:44:57