使用 .docx 导入和导出自定义节点
Available in Start planBetav0.13.0
@tiptap-pro/extension-export-docx 和 @tiptap-pro/extension-import-docx 扩展的最大优点之一是能够定义您 Tiptap 模式中的自定义节点应如何在 DOCX 中呈现。
这使您能够在导出的 Word 文件中保留特定于应用程序的内容。
导出自定义节点到 .docx
调用 editor.exportDocx() 时,可以在 ExportDocxOptions 参数中传递一个自定义节点定义数组。每个定义指定节点类型和渲染函数。
自定义节点约定
自定义节点转换器必须遵守底层 DOCX 生成库的要求。在实践中,DOCX 的自定义转换函数应返回该节点允许的 DOCX 元素之一:Paragraph 类(或 Paragraph 类的数组)、Table 类、TextRun 类、ExternalHyperlink 类,或者如果该节点应在输出中跳过,则返回 null。
定义自定义节点扩展
举例来说,假设你的编辑器有一个自定义节点类型 hintbox(一个带有提示样式的框)。你可以定义它在导出文档中应如何显示。
下面是 Hintbox 扩展的自定义节点示例:
import { mergeAttributes, Node } from '@tiptap/core'
export interface ParagraphOptions {
/**
* 段落节点的 HTML 属性。
* @default {}
* @example { class: 'foo' }
*/
HTMLAttributes: Record<string, any>
}
declare module '@tiptap/core' {
interface Commands<ReturnType> {
hintbox: {
/**
* 设置一个提示框
* @example editor.commands.setHintbox()
*/
setHintbox: () => ReturnType
/**
* 切换一个提示框
* @example editor.commands.toggleHintbox()
*/
toggleHintbox: () => ReturnType
}
}
}
/**
* 该扩展允许你创建提示框。
* @see https://www.tiptap.dev/api/nodes/paragraph
*/
export const Hintbox = Node.create<ParagraphOptions>({
name: 'hintbox',
priority: 1000,
addOptions() {
return {
HTMLAttributes: {
style: 'padding: 20px; border: 1px solid #b8d8ff; border-radius: 5px; background-color: #e6f3ff;',
},
}
},
group: 'block',
content: 'inline*',
parseHTML() {
return [{ tag: 'p' }]
},
renderHTML({ HTMLAttributes }) {
return ['p', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]
},
addCommands() {
return {
setHintbox:
() =>
({ commands }) => {
return commands.setNode(this.name)
},
toggleHintbox:
() =>
({ commands }) => {
return commands.toggleNode(this.name, 'paragraph')
},
}
},
addKeyboardShortcuts() {
return {
'Mod-Alt-h': () => this.editor.commands.toggleHintbox(),
}
},
})定义自定义节点渲染函数
我们将定义在导出文档中,Hintbox 自定义节点应如何渲染:
// 导入 ExportDocx 扩展
import {
convertTextNode,
Docx,
ExportDocx,
lineHeightToDocx,
pixelsToHalfPoints,
pointsToTwips,
} from '@tiptap-pro/extension-export-docx'
const editor = new Editor({
extensions: [
// 其他扩展 ...
ExportDocx.configure({
onCompleteExport: result => {
setIsLoading(false)
const blob = new Blob([result], {
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
})
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = 'export.docx'
a.click()
URL.revokeObjectURL(url)
},
exportType: 'blob',
customNodes: [
{
type: 'hintbox',
render: node => {
// 在这里我们定义自定义 Hintbox 节点在 DOCX 中的渲染方式。
// 根据文档,我们应该返回一个 DOCX 节点
// 这要么是一个段落,要么是一个段落的数组,或者是一个表格。
return new Docx.Paragraph({
children: node.content.map(content => convertTextNode(content)),
style: 'Hintbox', // 在这里我们将自定义样式应用于段落节点。
})
},
},
], // 自定义节点
styleOverrides: {
paragraphStyles: [
// 在这里我们定义自定义 Hintbox 节点的样式。
{
id: 'Hintbox',
name: 'Hintbox',
basedOn: 'Normal',
next: 'Normal',
quickFormat: false,
run: {
font: 'Aptos Light',
size: pixelsToHalfPoints(16),
},
paragraph: {
spacing: {
before: pointsToTwips(12),
after: pointsToTwips(12),
line: lineHeightToDocx(1),
},
border: {
// DOCX 颜色为十六进制,不带前导 #
top: { style: Docx.BorderStyle.SINGLE, size: 1, color: 'b8d8ff', space: 5 },
bottom: { style: Docx.BorderStyle.SINGLE, size: 1, color: 'b8d8ff', space: 5 },
right: { style: Docx.BorderStyle.SINGLE, size: 1, color: 'b8d8ff', space: 5 },
left: { style: Docx.BorderStyle.SINGLE, size: 1, color: 'b8d8ff', space: 5 },
},
shading: {
type: Docx.ShadingType.SOLID,
color: 'e6f3ff',
},
},
},
],
}, // 样式覆盖
}),
// 其他扩展 ...
],
// 其他编辑器设置 ...
})然后,在应用程序的后续阶段,您可以将编辑器内容导出为 DOCX 文件:
editor
.chain()
.exportDocx()
.run()您可以在 render 函数中使用 Docx 库类(Paragraph、TextRun、Table 等)构建任何支持的 DOCX 元素,这些类是通过从 @tiptap-pro/extension-export-docx 包的 Docx 导入提供的。