Docs

word-editor 文档

面向宿主业务系统的完整接入指南,覆盖 DOCX 展示与编辑、书签逻辑及视觉位置、定点内容插入、保存、导入导出、事件、类型、安全和生产发布。

快速开始

构建并导入浏览器运行时,页面中放置 <word-editor>。元素连接到 DOM 后,使用稳定的宿主接口导入 DOCX、监听状态并保存。

<word-editor id="editor" mode="edit" zoom="1"></word-editor>

<script type="module">
  await import("/word-editor-runtime-loader.mjs");

  const editor = document.querySelector("#editor");
  editor.addEventListener("ready", () => console.log("ready"));
  editor.addEventListener("changed", (event) => {
    console.log("dirty", event.detail.dirty);
  });
  editor.addEventListener("error", (event) => {
    console.error(event.detail.code, event.detail.message);
  });

  await editor.importDocument(file, { name: file.name });
  editor.insertContent("由业务系统写入", { at: "cursor" });
  const output = await editor.saveDocument();
</script>
运行时路径

源码构建或私有部署导入 /packages/word-editor/dist/index.js。本官网的授权 Cloudflare Pages 产物使用同源 /word-editor-runtime-loader.mjs;发布脚本会自动重写示例引用。

生命周期

宿主系统负责文件存储、权限、版本和并发控制;编辑器负责 DOCX 解析、呈现、编辑和序列化。生产接入应遵循同一条生命周期。

  1. 挂载把元素连接到 DOM,等待 ready
  2. 导入调用 importDocument()loadBlank(),等待 loaded
  3. 编辑通过 ribbon、exec()、插入 API 或书签 API 修改内容。
  4. 跟踪监听 changed,并以 editor.dirty 控制保存和离开页面提示。
  5. 保存串行调用 saveDocument(),上传成功后再确认业务版本。
  6. 销毁仅在宿主真正卸载编辑器时调用 destroy()
const editor = document.querySelector("word-editor");
let saving = false;

editor.addEventListener("changed", ({ detail }) => {
  saveButton.disabled = saving || !detail.dirty;
});

async function saveToBusinessSystem(documentId, version) {
  if (saving) return;
  saving = true;
  try {
    const blob = await editor.saveDocument();
    await businessApi.putDocument(documentId, blob, {
      name: editor.documentName,
      version,
    });
  } finally {
    saving = false;
  }
}

导入、保存与导出

稳定宿主接口使用明确的业务名称;旧的 load()save() 保持兼容。

方法输入 / 返回行为
importDocument(input, options?)File | Blob | ArrayBuffer | Uint8Array导入 DOCX,触发 loaded,重置 dirty。
load(input, name?)File | Blob | ArrayBuffer兼容加载入口。
loadBlank(name?)Promise<void>创建空白 DOCX。
saveDocument()Promise<Blob>序列化为 DOCX Blob,触发 saved
exportDocument()Promise<Blob>导出适合下载或上传的 Blob。
exportDocument({ output: "array-buffer" })Promise<ArrayBuffer>导出适合二进制传输的字节。
save()Promise<Blob>兼容保存入口。
const response = await fetch(`/api/documents/${documentId}`);
if (!response.ok) throw new Error(`open failed: ${response.status}`);

const blob = await response.blob();
await editor.importDocument(blob, {
  name: response.headers.get("x-document-name") || "document.docx",
});

const output = await editor.exportDocument();
await fetch(`/api/documents/${documentId}`, {
  method: "PUT",
  headers: { "Content-Type": output.type },
  body: output,
});
保存边界

saved 表示编辑器已经完成序列化,不代表服务器已经持久化。宿主必须自行处理上传失败、版本冲突、重试和原文件保留。

定点插入内容

insertContent(content, options?) 是统一插入管线。当前只接收安全纯文本;不会解析 HTML,换行会转为文档换行。

editor.insertContent("替换当前选区或写入光标处");
editor.insertContent("文档前缀", { at: "document-start" });
editor.insertContent("文档后缀", { at: "document-end" });
editor.insertContent({ type: "text", text: "签署人:王宇" }, {
  at: "bookmark",
  bookmark: "CustomerSignature",
  placement: "start",
});
at必填选项语义
cursor替换当前选区,或在光标处插入。默认值。
document-start在正文起点插入。
document-end在正文末尾插入。
bookmarkbookmark,可选 placement在书签边界插入。

书签 placement 支持 beforestartendafter,默认是 startinsertText()insertTextAtBookmark() 是兼容快捷方法。

方法返回 boolean。成功接受操作返回 true;只读、受保护文档、书签不存在或当前位置不可编辑时返回 false

书签管理与位置

书签是文档内稳定锚点,支持点书签、范围书签以及导入文档中的兼容书签。查询结果同时提供逻辑位置和当前渲染位置。

listBookmarks()列出全部书签及其名称、ID、类型、文本、页码和位置。
hasBookmark(name)按名称或 ID 判断书签是否存在。
findBookmark(name)返回一个 WordEditorBookmarkInfo
getBookmarkPosition(name)重新计算并返回最新的起点与终点位置。
gotoBookmark(name)滚动到书签并恢复其选区,成功返回 true
addBookmark(name?)从当前光标或选区创建书签,返回最终唯一名称。
deleteBookmark(name)删除标记但保留被标记内容。
insertTextAtBookmark(name, text)通过统一插入管线写入书签起点。
const bookmark = editor.findBookmark("CustomerSignature");
const position = editor.getBookmarkPosition("CustomerSignature");

console.log({
  type: bookmark?.type,             // "point" | "range" | "legacy"
  page: position?.start.page,       // 1-based
  blockIndex: position?.start.blockIndex,
  offsetInBlock: position?.start.offsetInBlock,
  documentOffset: position?.start.documentOffset,
  pageOffset: position?.start.pageOffset,
  viewportRect: position?.start.viewportRect,
});

editor.gotoBookmark("CustomerSignature");
字段坐标系 / 单位说明
page从 1 开始当前分页中的页码。
blockIndex从 0 开始正文块索引。
offsetInBlock从 0 开始,UTF-16块内文本偏移。
documentOffset从 0 开始,UTF-16正文逻辑偏移,不含页眉页脚。
pageOffsetCSS px相对当前渲染页左上角。
viewportRectCSS px相对浏览器视口的瞬时矩形。
坐标有效期

缩放、窗口尺寸、字体加载、内容编辑或重新分页后,视觉坐标可能变化。需要定位浮层或业务标注时,应重新调用 getBookmarkPosition(),不要长期缓存 pageOffsetviewportRect

完整 API

Element

word-editor 是原生 Custom Element。默认包入口会自动注册,也可以从模块中手动调用 defineWordEditorElement(tagName)

Attribute Values Default 说明
mode edit, view edit 编辑或只读查看模式,可通过 setMode() 同步。
engine ts ts 当前生产引擎为纯 TypeScript DOCX runtime。
zoom 正数 1 页面缩放比例,可通过 setZoom() 更新。
auto-font-gateway boolean attribute off 启用后台字体网关加载,不阻塞首屏文档呈现。
font-gateway-url URL 默认网关 字体 manifest 地址;当前可配置为 https://font.flyfish.group/manifest.json
font-gateway-limit 正整数 默认限制 自动加载字体数量上限,用于控制网络和内存预算。
license-required boolean attribute off 启用授权门禁;生产环境建议开启。
license-feature string runtime 默认 授权校验使用的功能名。

Methods

importDocument(input, options?)从 File、Blob、ArrayBuffer 或 Uint8Array 导入 DOCX。
load(input, name?)兼容文档加载入口。
loadBlank(name?)创建空白文档,默认文件名为 document.docx
saveDocument()保存当前文档为 DOCX Blob,并触发 saved
exportDocument(options?)导出 Blob 或 ArrayBuffer。
save()兼容保存入口。
insertContent(content, options?)在光标、文档首末或书签边界插入安全纯文本。
insertText(text)在当前光标或选区插入安全纯文本。
listBookmarks() / findBookmark(name)列出或查询书签信息。
getBookmarkPosition(name) / gotoBookmark(name)读取书签位置或导航到书签。
addBookmark(name?) / deleteBookmark(name)创建或删除书签标记。
exec(command, value?)执行 ribbon/API 命令,例如 boldfontNametoggleRuler
insertTable(rows?, columns?)在当前选区插入表格。
insertImage(input, options?)插入图片,支持 alt、mimeType 和最大宽度。
registerFont(font)注册单个字体源。
registerFonts(fonts)批量注册字体源。
importFont(input, options?)导入字体文件,可写入持久字体仓库。
loadFontGatewayFonts(options?)按 manifest 后台加载字体网关字体。
loadRepositoryFonts(manifestUrl?, persist?, options?)从自定义字体仓库加载字体。
listPersistedFonts()列出浏览器端已持久化字体。
clearPersistedFonts()清理浏览器端字体缓存。
setMode(mode)切换 editview
setZoom(value)设置缩放比例。
reflowPages()请求重新分页和布局。
getRuntimeStatus()读取运行时状态、页数、字体、dirty 状态和布局信息。
destroy()销毁引擎并清空挂载点。

Properties

dirty当前文档是否存在尚未序列化的修改。
documentName当前文档名称;尚未加载时为 undefined
modeeditview
engineKind当前为 ts
zoom当前页面缩放比例。

命令

命令由 exec(command, value?) 统一执行。格式类命令会优先作用于当前选区;视图类命令会更新对应 UI 状态。

格式

bold, italic, underline, strikeThrough, fontName, fontSizePt, foreColor, hiliteColor, removeFormat, subscript, superscript

段落与页面

justifyLeft, justifyCenter, justifyRight, justifyFull, insertOrderedList, insertUnorderedList, lineSpacing, setPageSize, setMargins, setOrientation

对象

insertTable, insertShape, insertTextBox, insertWordArt, insertSmartArt, insertChart, insertEquation, insertHyperlink, insertComment

审阅与视图

toggleTrackChanges, acceptRevision, rejectRevision, updateFields, toggleRuler, toggleNavigation, togglePageEnds, toggleGridlines, toggleDarkMode

事件

Event detail 用途
ready none 编辑器引擎已挂载。
loaded { name, engine, pageCount, fonts, persistedFonts } 文档加载完成,可同步标题、页数和字体状态。
changed { dirty } 内容发生变化或保存后 dirty 状态变化。
saved { name, blob } 保存完成,宿主应用可上传 Blob。
error { code, message, detail } 授权、加载、保存或命令异常。
word-editor-operation operation commit 编辑操作桥接事件,适合审计、协作或回放。
word-editor-action { action, ...detail } 宿主边界动作事件,例如共享、外部服务、插件任务。
word-editor-semantic-paste semantic paste payload 结构化粘贴结果和操作摘要。

TypeScript

构建产物会生成公共声明文件。应用可直接导入元素类和所有宿主 API 类型,不需要自行维护重复接口。

import {
  WordEditorElement,
  type WordEditorBookmarkInfo,
  type WordEditorBookmarkPosition,
  type WordEditorContentInput,
  type WordEditorDocumentExportOptions,
  type WordEditorDocumentImportOptions,
  type WordEditorDocumentInput,
  type WordEditorDocumentPosition,
  type WordEditorInsertContentOptions,
  type WordEditorSaveResult,
} from "@word-editor/word-editor";

const editor = document.querySelector<WordEditorElement>("word-editor");
if (!editor) throw new Error("word-editor is not mounted");

const options: WordEditorInsertContentOptions = {
  at: "bookmark",
  bookmark: "CustomerSignature",
  placement: "start",
};
editor.insertContent("已签署", options);

源码或私有包使用生成的 dist/index.d.ts。官网授权运行时是浏览器交付入口,不提供在线类型解析;项目编译时应依赖同版本私有包或声明产物。

字体网关

生产建议开启异步字体加载:先呈现文档,再在后台下载字体和触发布局刷新,避免首屏被字体阻塞。

<word-editor
  auto-font-gateway
  font-gateway-url="https://font.flyfish.group/manifest.json"
  font-gateway-limit="32">
</word-editor>

宿主也可以直接调用 registerFont()loadRepositoryFonts() 控制字体来源、授权和缓存策略。

错误、安全与授权

错误语义

异步生命周期、导入、保存和运行时失败会抛出异常,并通过 error 事件向宿主报告。编辑类同步方法在操作不可接受时返回 false

editor.addEventListener("error", ({ detail }) => {
  logEditorError(detail.code, detail.message, detail.detail);
  showDocumentError(detail.message);
});

try {
  await editor.importDocument(input, { name });
} catch (error) {
  showRetryAction(error);
}

if (!editor.insertContent("审批意见")) {
  showToast("当前位置不可编辑或文档为只读模式");
}

宿主安全边界

  • 在服务端校验文件类型、文件大小、租户权限和病毒扫描结果;不要只信任浏览器 MIME。
  • 内容插入 API 仅接受纯文本,不要把不可信 HTML 直接写入编辑器 DOM。
  • 保存期间禁用重复提交;使用业务版本号或 ETag 处理并发覆盖。
  • 新 Blob 成功上传并确认版本之前保留原文档,不要把本地序列化等同于远端持久化。
  • 离开页面前根据 dirty 提示,并在宿主应用中记录 error 技术细节。

生产授权

生产构建包含 office-preview-license.json、授权运行时和 WASM 门禁。启用 license-required 后,元素挂载时会校验授权;失败时触发 error 并显示授权错误面板。

<word-editor
  license-required
  license-feature="word-editor-production">
</word-editor>

部署

当前生产目标为 https://docx-editor.pages.dev。先签发并提交运行授权,再从该 commit 创建全新的干净 worktree。发布脚本会重建 runtime、复制站点和 Markdown 文档、复制授权资产与 WASM、写入 Cloudflare 控制文件、生成 release metadata,并把同 commit 的对应源码归档一起封装。完整步骤见 Deployment Guide

# 在已提交发布 SHA 的全新 clean worktree 中
npm ci
npm run build:cloudflare
npm run deploy:cloudflare
/产品主页和生产入口。
/docs/本开发文档;/docs/*.md 提供版本化 Markdown 原文。
/examples/demo/完整在线编辑器。
/examples/integration/第三方宿主 API 集成 Demo。
/word-editor-runtime-loader.mjs授权发布使用的同源运行时加载入口。
/auth/*/wasm/*授权运行时和 Office 解析核心。
/word-editor-release.json版本、产物和部署来源元数据。
/source/current.tar.gz与当前线上运行时同 commit 的完整对应源码。
/source/current.tar.gz.sha256对应源码归档的 SHA-256 校验文件。
/source/index.json源码 commit、不可变归档地址、摘要和大小的机器可读索引。

生产运维

  • 上线前验证根主页、文档页、完整 Demo、集成 Demo、授权文件、WASM MIME 和 release metadata。
  • 验证导入、编辑、书签查询、四种插入目标、保存 Blob 和 ArrayBuffer 导出。
  • 对变更范围执行受影响测试;涉及编辑器 runtime 时再运行浏览器端 smoke 和核心回归。
  • 字体仓库、授权域名和 Cloudflare 项目名应随发布记录一起审计。
  • 宿主应用应处理 changedsavederror,并在离开页面前处理 dirty 状态。
  • 监控导入失败率、保存耗时、上传失败、版本冲突和授权错误,不记录文档正文。

详细资料:部署指南 授权指南 测试指南