端到端演练:导入、编辑、导出

Beta

本指南将带你从一个空项目开始,端到端完成可用的 DOCX 导入和导出。我们将使用 ConvertKit 配置编辑器,接入一个文件输入,通过 Conversion 服务上传 DOCX,并将文档再导出回 DOCX。如果你想要分页式编辑器,第 6 步还会展示如何在此基础上叠加 Pages 扩展

前置条件

1. 安装 Conversion 技术栈

npm install @tiptap-pro/extension-convert-kit \
            @tiptap-pro/extension-import-docx \
            @tiptap-pro/extension-export-docx

为什么始终使用 ConvertKit

ConvertKit 是 Conversion 的标准编辑器套件。它注册了 DOCX 感知的 schema (段落间距、图片裁剪、表格单元格格式),这些内容由导入服务生成并由 导出服务使用。不要替换为 StarterKit;否则在往返转换中你会丢失这些属性。

2. 使用 ConvertKit 设置编辑器

import { Editor } from '@tiptap/core'
import { ConvertKit } from '@tiptap-pro/extension-convert-kit'
import { ImportDocx } from '@tiptap-pro/extension-import-docx'
import { ExportDocx } from '@tiptap-pro/extension-export-docx'

const editor = new Editor({
  element: document.querySelector('#editor'),
  extensions: [
    ConvertKit,
    ImportDocx.configure({
      token: 'YOUR_JWT', // 在服务端生成
    }),
    ExportDocx.configure({
      onCompleteExport: (result) => {
        // 第 5 步会在这里补充
      },
    }),
  ],
})

签名令牌

始终在服务器上对令牌进行签名。切勿在浏览器代码中暴露你的签名密钥。有关如何对令牌进行签名,请参见 身份验证;有关 Convert 令牌所需操作,请参见 转换安装指南

3. 接入 DOCX 导入

在页面上添加一个文件输入,并将选中的文件传给编辑器的 import 命令:

<input type="file" id="docx-input" accept=".docx" />
const input = document.querySelector<HTMLInputElement>('#docx-input')!

input.addEventListener('change', () => {
  const file = input.files?.[0]
  if (!file) return

  editor.chain().focus().importDocx({ file }).run()
})

这就是完整流程。转换服务接收 DOCX,返回 Tiptap JSON,编辑器使用 ConvertKit 的 schema 将其渲染出来。

4. 自行处理导入结果

默认导入会替换编辑器内容。若要校验、转换或展示错误,可以传入 onImport 回调:

editor
  .chain()
  .focus()
  .importDocx({
    file,
    onImport(context) {
      if (context.error) {
        console.error('导入失败:', context.error)
        return
      }

      // 在这里检查或转换 `context.content`。若要原样使用它,请调用 setEditorContent()。
      // 若要替换为你自己的转换结果,请使用 editor.commands.setContent()。
      context.setEditorContent()
    },
  })
  .run()

content 对象是普通的 Tiptap JSON。记录它是了解转换器实际生成了什么的最快方式,这在某个功能渲染异常时非常有用。

5. 配置 DOCX 导出

onCompleteExport 回调中补上下载触发逻辑:

ExportDocx.configure({
  onCompleteExport: (result) => {
    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 = 'document.docx'
    a.click()
    URL.revokeObjectURL(url)
  },
  exportType: 'blob', // 默认值;这里显式写出以便更清楚
})

从按钮触发导出:

document.querySelector('#export')!.addEventListener('click', () => {
  editor.commands.exportDocx()
})

DOCX 导出是客户端执行的:不需要 JWT、不需要 App ID、也不需要 API 调用。转换发生在扩展本身内部。

往返转换不会逐字节完全一致

一些功能(上下标标记、段落行高、浮动表格)目前往返转换并不完美。 请查看完整的 功能支持矩阵。 不要指望 DOCX → 编辑 → DOCX 的循环会生成与原文件逐字节完全一致的结果。

6. (可选)添加 Pages 以实现分页渲染

如果你希望编辑器看起来像一份真正的文档,带有分页边界、页眉页脚和页面格式,可以在相同设置的基础上添加 Pages 扩展 和 PagesTableKit:

npm install @tiptap-pro/extension-pages-tablekit @tiptap-pro/extension-pages
import { ConvertKit } from '@tiptap-pro/extension-convert-kit'
import { TableKit }   from '@tiptap-pro/extension-pages-tablekit'
import { Pages }      from '@tiptap-pro/extension-pages'
import { ImportDocx } from '@tiptap-pro/extension-import-docx'
import { ExportDocx } from '@tiptap-pro/extension-export-docx'

const editor = new Editor({
  extensions: [
    ConvertKit.configure({ table: false }), // 禁用 ConvertKit 自带的表格
    TableKit,                                // 改用适合分页的表格
    Pages.configure({
      pageFormat: 'A4',
      header: '我的文档',
      footer: '第 {page} 页,共 {total} 页',
    }),
    ImportDocx.configure({ token: 'YOUR_JWT' }),
    ExportDocx.configure({ onCompleteExport: /* ... */ }),
  ],
})

与第 2 步的差异:

  • 禁用 ConvertKit 的表格({ table: false });ConvertKit 内置的表格不适合分页。
  • 添加来自 extension-pages-tablekitTableKit
  • 添加 Pages.configure({...})

导入的文档现在会应用页眉、页脚和页面格式进行渲染。导出路径保持不变:editor.commands.exportDocx() 仍然可用,并且导出的 DOCX 会保留 Pages 覆盖层中的页眉和页脚。

Pages 的重要限制

在发布前请阅读 Pages 限制说明 页面。比页面还高的表格和其他不可拆分块可能会让布局进入无限循环。

预期结果

  • 导入始终通过服务进行。 即使是一个很小的 DOCX,也会调用转换服务进行解析。该服务需要已签名的 JWT。
  • 导出是本地进行的。 DOCX 导出在浏览器中运行;不需要认证,也不会发起网络请求。
  • 往返转换偏差是真实存在的。 对矩阵中无法往返转换的功能(如下标、行高)要提前规划:要么在编辑器 schema 中避免这些功能,要么接受这种偏差。

不要期望

  • OCR 或扫描版 PDF 处理。 转换处理的是结构化文档,而不是整页位图输入。
  • 在此设置中的实时协作。 如果你需要多人编辑,请搭配 Tiptap Collaboration 产品使用。在与 Pages 结合使用时,请参见 向 Pages 添加协作
  • 异步任务控制。 该服务会对每个请求同步响应。对于非常大的文档,请在你这边规划好超时设置。

下一步