如果你想在 tiptap 编辑器设置显示表格,你可以是使用 table 扩展,它可以渲染成 html 的 table 标签,他可以合并单元格、添加删除行等等。
npm install @tiptap/extension-table @tiptap/extension-table-row @tiptap/extension-table-header @tiptap/extension-table-cell
Table 的配置项。
Table.configure({
HTMLAttributes: {
class: 'my-custom-class',
},
//是否允许缩放
resizable:false,
//拖动时边框大小
handleWidth:5,
//单元格最小宽度
cellMinWidth:25,
View:"TableView",
//最好一列是否自适应宽度
lastColumnResizable:true,
allowTableNodeSelection:false
})
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*',
})
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;
}