tiptap 中文文档

tiptap Table 表格扩展

如果你想在 tiptap 编辑器设置显示表格,你可以是使用 table 扩展,它可以渲染成 htmltable 标签,他可以合并单元格、添加删除行等等。

Install 安装

npm install @tiptap/extension-table @tiptap/extension-table-row @tiptap/extension-table-header @tiptap/extension-table-cell

Settings 配置

Table 的配置项。

Table.configure({
  HTMLAttributes: {
    class: 'my-custom-class',
  },
  //是否允许缩放
  resizable:false,
  //拖动时边框大小
  handleWidth:5,
  //单元格最小宽度
  cellMinWidth:25,
  View:"TableView",
  //最好一列是否自适应宽度
  lastColumnResizable:true,
  allowTableNodeSelection:false
})

Commands 命令

insertTable 插入表格,你可以制定插入多少行、多少列。

//插入表格
editor.commands.insertTable();
//插入3行3列和表头
editor.commands.insertTable({ rows: 3, cols: 3, withHeaderRow: true }

addColumnBefore 

//当前选中列之前插入一个列
editor.commands.addColumnBefore();

addColumnAfter 

//当前选中列之后插入一个列
editor.commands.addColumnAfter();

deleteColumn 

//删除当前选中的列
editor.commands.deleteColumn();

addRowBefore 

//选中行之上插入一行
editor.commands.addRowBefore();

addRowAfter 

//在选中行之后插入一行
editor.commands.addRowAfter();

deleteRow 

//删除选中行
editor.commands.deleteRow();

deleteTable 

//删除整个表格
editor.commands.deleteTable();

mergeCells 

//合表选中的单元格
editor.commands.mergeCells();

splitCell 

//拆分选中的单元格
editor.commands.splitCell();

toggleHeaderColumn 

//切换选中列为表头列
editor.commands.toggleHeaderColumn();

toggleHeaderRow 

//切换选中行为表头行
editor.commands.toggleHeaderRow();

toggleHeaderCell 

//切换选中单元格为表头
editor.commands.toggleHeaderCell();

mergeOrSplit 

//合并或拆分选中项
editor.commands.mergeOrSplit();

setCellAttribute 

editor.commands.setCellAttribute('customAttribute', 'value')
editor.commands.setCellAttribute('backgroundColor', '#000')

goToNextCell 

editor.commands.goToNextCell();

goToPreviousCell 

editor.commands.goToPreviousCell();

fixTables 

editor.commands.fixTables();

不使用表头 

// Table rows without table headers
TableRow.extend({
  content: 'tableCell*',
})

源代码

table 源代码

table-row 源代码

table-cell 源代码

table-header 源代码

在线例子

vue 在线例子

Table 例子

  • Vue 例子

  • React 例子

  • React CSS

<template>
  <div v-if="editor">
    <button @click="editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()">
      insertTable
    </button>
    <button @click="editor.chain().focus().addColumnBefore().run()">
      addColumnBefore
    </button>
    <button @click="editor.chain().focus().addColumnAfter().run()">
      addColumnAfter
    </button>
    <button @click="editor.chain().focus().deleteColumn().run()">
      deleteColumn
    </button>
    <button @click="editor.chain().focus().addRowBefore().run()">
      addRowBefore
    </button>
    <button @click="editor.chain().focus().addRowAfter().run()">
      addRowAfter
    </button>
    <button @click="editor.chain().focus().deleteRow().run()">
      deleteRow
    </button>
    <button @click="editor.chain().focus().deleteTable().run()">
      deleteTable
    </button>
    <button @click="editor.chain().focus().mergeCells().run()">
      mergeCells
    </button>
    <button @click="editor.chain().focus().splitCell().run()">
      splitCell
    </button>
    <button @click="editor.chain().focus().toggleHeaderColumn().run()">
      toggleHeaderColumn
    </button>
    <button @click="editor.chain().focus().toggleHeaderRow().run()">
      toggleHeaderRow
    </button>
    <button @click="editor.chain().focus().toggleHeaderCell().run()">
      toggleHeaderCell
    </button>
    <button @click="editor.chain().focus().mergeOrSplit().run()">
      mergeOrSplit
    </button>
    <button @click="editor.chain().focus().setCellAttribute('colspan', 2).run()">
      setCellAttribute
    </button>
    <button @click="editor.chain().focus().fixTables().run()">
      fixTables
    </button>
    <button @click="editor.chain().focus().goToNextCell().run()">
      goToNextCell
    </button>
    <button @click="editor.chain().focus().goToPreviousCell().run()">
      goToPreviousCell
    </button>
    <editor-content :editor="editor" />
  </div>
</template>
<script>
import Document from '@tiptap/extension-document'
import Gapcursor from '@tiptap/extension-gapcursor'
import Paragraph from '@tiptap/extension-paragraph'
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 Text from '@tiptap/extension-text'
import { Editor, EditorContent } from '@tiptap/vue-3'

export default {
  components: {
    EditorContent,
  },
  data() {
    return {
      editor: null,
    }
  },
  mounted() {
    this.editor = new Editor({
      extensions: [
        Document,
        Paragraph,
        Text,
        Gapcursor,
        Table.configure({
          resizable: true,
        }),
        TableRow,
        TableHeader,
        TableCell,
      ],
      content: `
        <table>
          <tbody>
            <tr>
              <th>Name</th>
              <th colspan="3">Description</th>
            </tr>
            <tr>
              <td>Cyndi Lauper</td>
              <td>singer</td>
              <td>songwriter</td>
              <td>actress</td>
            </tr>
          </tbody>
        </table>
      `,
    })
  },
  beforeUnmount() {
    this.editor.destroy()
  },
}
</script>
<style>
.ProseMirror {
  table {
    border-collapse: collapse;
    table-layout: fixed;
    width: 100%;
    margin: 0;
    overflow: hidden;
    td,
    th {
      min-width: 1em;
      border: 2px solid #ced4da;
      padding: 3px 5px;
      vertical-align: top;
      box-sizing: border-box;
      position: relative;
      > * {
        margin-bottom: 0;
      }
    }
    th {
      font-weight: bold;
      text-align: left;
      background-color: #f1f3f5;
    }
    .selectedCell:after {
      z-index: 2;
      position: absolute;
      content: "";
      left: 0; right: 0; top: 0; bottom: 0;
      background: rgba(200, 200, 255, 0.4);
      pointer-events: none;
    }
    .column-resize-handle {
      position: absolute;
      right: -2px;
      top: 0;
      bottom: -2px;
      width: 4px;
      background-color: #adf;
      pointer-events: none;
    }
    p {
      margin: 0;
    }
  }
}
.tableWrapper {
  padding: 1rem 0;
  overflow-x: auto;
}
.resize-cursor {
  cursor: ew-resize;
  cursor: col-resize;
}
</style>
import './styles.scss'

import Document from '@tiptap/extension-document'
import Gapcursor from '@tiptap/extension-gapcursor'
import Paragraph from '@tiptap/extension-paragraph'
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 Text from '@tiptap/extension-text'
import { EditorContent, useEditor } from '@tiptap/react'
import React from 'react'

export default () => {
  const editor = useEditor({
    extensions: [
      Document,
      Paragraph,
      Text,
      Gapcursor,
      Table.configure({
        resizable: true,
      }),
      TableRow,
      TableHeader,
      TableCell,
    ],
    content: `
        <table>
          <tbody>
            <tr>
              <th>Name</th>
              <th colspan="3">Description</th>
            </tr>
            <tr>
              <td>Cyndi Lauper</td>
              <td>singer</td>
              <td>songwriter</td>
              <td>actress</td>
            </tr>
          </tbody>
        </table>
      `,
  })
  if (!editor) {
    return null
  }
  return (
    <>
      <button
        onClick={() => editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()
        }
      >
        insertTable
      </button>
      <button onClick={() => editor.chain().focus().addColumnBefore().run()}>
        addColumnBefore
      </button>
      <button onClick={() => editor.chain().focus().addColumnAfter().run()}>addColumnAfter</button>
      <button onClick={() => editor.chain().focus().deleteColumn().run()}>deleteColumn</button>
      <button onClick={() => editor.chain().focus().addRowBefore().run()}>addRowBefore</button>
      <button onClick={() => editor.chain().focus().addRowAfter().run()}>addRowAfter</button>
      <button onClick={() => editor.chain().focus().deleteRow().run()}>deleteRow</button>
      <button onClick={() => editor.chain().focus().deleteTable().run()}>deleteTable</button>
      <button onClick={() => editor.chain().focus().mergeCells().run()}>mergeCells</button>
      <button onClick={() => editor.chain().focus().splitCell().run()}>splitCell</button>
      <button onClick={() => editor.chain().focus().toggleHeaderColumn().run()}>
        toggleHeaderColumn
      </button>
      <button onClick={() => editor.chain().focus().toggleHeaderRow().run()}>
        toggleHeaderRow
      </button>
      <button onClick={() => editor.chain().focus().toggleHeaderCell().run()}>
        toggleHeaderCell
      </button>
      <button onClick={() => editor.chain().focus().mergeOrSplit().run()}>mergeOrSplit</button>
      <button onClick={() => editor.chain().focus().setCellAttribute('colspan', 2).run()}>
        setCellAttribute
      </button>
      <button onClick={() => editor.chain().focus().fixTables().run()}>fixTables</button>
      <button onClick={() => editor.chain().focus().goToNextCell().run()}>goToNextCell</button>
      <button onClick={() => editor.chain().focus().goToPreviousCell().run()}>
        goToPreviousCell
      </button>
      <EditorContent editor={editor} />
    </>
  )
}
.ProseMirror {
  table {
    border-collapse: collapse;
    margin: 0;
    overflow: hidden;
    table-layout: fixed;
    width: 100%;
    td,
    th {
      border: 2px solid #ced4da;
      box-sizing: border-box;
      min-width: 1em;
      padding: 3px 5px;
      position: relative;
      vertical-align: top;
      > * {
        margin-bottom: 0;
      }
    }
    th {
      background-color: #f1f3f5;
      font-weight: bold;
      text-align: left;
    }
    .selectedCell:after {
      background: rgba(200, 200, 255, 0.4);
      content: "";
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
      pointer-events: none;
      position: absolute;
      z-index: 2;
    }
    .column-resize-handle {
      background-color: #adf;
      bottom: -2px;
      position: absolute;
      right: -2px;
      pointer-events: none;
      top: 0;
      width: 4px;
    }
    p {
      margin: 0;
    }
  }
}

.tableWrapper {
  padding: 1rem 0;
  overflow-x: auto;
}

.resize-cursor {
  cursor: ew-resize;
  cursor: col-resize;
}
Catalog
快速入门 Guide 向导 API 列表 tiptap 方法 tiptap 属性 titap 配置 commands 命令 nodes 节点 Blockquote 引用扩展 BulletList 无序序列扩展 CodeBlock 代码块扩展 CodeBlockLowlight 代码高亮 Document 节点 HardBreak 换行节点 Heading 标题节点 HorizontalRule 横线节点 Image 图片扩展 ListItem 节点 Mention 提及节点 OrderedList 有序列节点 Paragraph 段落节点 Table 表格扩展 TaskList 任务列表 TaskItem 任务列表项 Text 节点 marks 标记 extensions 扩展