使用 .docx 导入和导出自定义节点
@tiptap-pro/extension-export-docx 和 @tiptap-pro/extension-import-docx 扩展的最大优点之一是能够定义您 Tiptap 模式中的自定义节点应如何在 DOCX 中呈现。
这使您能够在导出的 Word 文件中保留特定于应用程序的内容。
自定义节点规范
自定义节点转换器必须遵循底层 DOCX 生成库的要求。在实践中,自定义转换函数返回的 DOCX 应该是该节点的允许元素之一:一个 Paragraph 类(或一个 Paragraph 类的数组)、一个 Table 类,或如果节点应该在输出中被跳过则返回 null。
导出自定义节点至 .docx
调用 editor.exportDocx() 时,可以在 ExportDocxOptions 参数中传递一个自定义节点定义数组。每个定义指定节点类型和渲染函数。
为了举例,假设您的编辑器有一个自定义节点类型 hintbox(一个提示框样式的盒子)。您可以定义它在 DOCX 中的外观。
以下是 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 自定义节点在 DOCX 中的渲染方式:
// 导入 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 导入提供的。
从 .docx 导入自定义节点
在导入 DOCX 文件时,您还可以定义自定义节点应如何转换回 Tiptap 节点。这是通过将自定义节点定义数组传递给 import 命令来完成的。
import { Import } from '@tiptap-pro/extension-import-docx'
// ... 在您的编辑器或 useEditor 设置中:
Import.configure({
appId: 'your-app-id',
token: 'your-jwt',
// 注意:这仅用于演示目的
endpoint: 'https://your-endpoint.com',
imageUploadCallbackUrl: 'https://your-endpoint.com/image-upload',
// Promisemirror 自定义节点映射
promisemirrorNodes: {
Hintbox: 'hintbox',
},
}),@tiptap-pro/extension-import-docx 的最新版本提供了 promisemirrorNodes 配置选项。此选项允许您将 DOCX 中的自定义节点映射到您的 Tiptap 模式。在上例中,我们将 DOCX 的 Hintbox 自定义节点映射到 Tiptap 模式中的 hintbox 自定义节点。这样,当导入包含 Hintbox 自定义节点的 DOCX 文件时,它会转换为 Tiptap 中的 hintbox 节点。
DOCX, "prosemirrorNodes" 和 "prosemirrorMarks"
请注意,promisemirrorNodes 和 prosemirrorMarks 选项仅在您导入 .docx 文件时有效。如果您导入另一种类型的文件,例如 .odt 文件,则会使用 /import 端点而不是 /import-docx 端点,promisemirrorNodes 和 prosemirrorMarks 选项将不可用,因此您需要依赖于 自定义节点和标记映射 API 处理这些端点。