为长文档创建目录,既能让读者快速定位章节内容,也便于在文档结构变动后重新同步条目与页码。本文以一份《Spire.Doc 开发指南》为例,介绍如何从零新建一份带有多级标题的 Word 文档,并为其添加内容目录。Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端直接构建和编辑 Word 文档,通过虚拟文件系统(VFS)管理字体资源,无需后端服务支持。
本文介绍两个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。以下示例默认已安装 Spire.Doc 并完成 WebAssembly 模块初始化。
添加默认目录
在 Word 中,目录本质上是一个 TOC 域,其条目来自文档中应用了标题样式的段落。创建默认目录的核心流程分为三个阶段:首先通过 FetchFileToVFS 将字体文件载入 WASM 虚拟文件系统;然后实例化 Document 并通过 AddSection、AddParagraph 构建内容,对需要出现在目录中的段落调用 ApplyStyle 应用标题样式,再通过 AppendTOC 在文档开头插入目录域;最后调用 UpdateTableOfContents 填充条目与页码,保存文档后从 VFS 读取生成的文件,封装为 Blob 后触发浏览器下载。
示例文档共包含三章、十二个多级标题,涵盖 Heading 1 至 Heading 3 三个层级,便于观察目录对多级标题的收录效果。
function App() {
const AddTableOfContentsToNewDocument = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 确保 WASM 模块完全加载完成
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将字体载入 VFS
await window.spire.FetchFileToVFS('msyh.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 创建文档实例并添加节
const doc = new docModule.Document();
let section = doc.AddSection();
// 在文档开头插入目录域,收集 Heading 1 至 Heading 3 的条目
let tocPara = section.AddParagraph();
tocPara.AppendTOC(1, 3);
// 添加文档标题
let characterFormat = new docModule.CharacterFormat(doc);
characterFormat.FontName ="微软雅黑";
let title = section.AddParagraph();
let titleRun = title.AppendText("Spire.Doc 开发指南");
titleRun.ApplyCharacterFormat(characterFormat);
titleRun.CharacterFormat.FontSize = 24;
title.Format.HorizontalAlignment = docModule.HorizontalAlignment.Center;
// 第一章 概述(一级标题)
let p = section.AddParagraph();
p.AppendText("第一章 概述").ApplyCharacterFormat(characterFormat);;
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading1 });
section.AddParagraph().AppendText("Spire.Doc for JavaScript 让开发者可以直接在浏览器中创建、编辑与保存 Word 文档,整个过程无需任何后端服务参与。").ApplyCharacterFormat(characterFormat);;
// 1.1 什么是 Spire.Doc for JavaScript(二级标题)
p = section.AddParagraph();
p.AppendText("1.1 什么是 Spire.Doc for JavaScript").ApplyCharacterFormat(characterFormat);;
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
section.AddParagraph().AppendText("它是一套基于 WebAssembly 的 Word 文档处理库,通过虚拟文件系统(VFS)管理字体与文档文件,并提供与 .NET 版一致的 API 形态。").ApplyCharacterFormat(characterFormat);;
// 1.2 适用场景(二级标题)
p = section.AddParagraph();
p.AppendText("1.2 适用场景").ApplyCharacterFormat(characterFormat);;
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
section.AddParagraph().AppendText("适用于在线合同签署、报表批量生成、简历模板填充等需要在客户端完成文档处理的场景。").ApplyCharacterFormat(characterFormat);;
// 第二章 核心能力(一级标题)
p = section.AddParagraph();
p.AppendText("第二章 核心能力").ApplyCharacterFormat(characterFormat);;
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading1 });
section.AddParagraph().AppendText("Spire.Doc for JavaScript 覆盖了文档处理的完整链路,从内容构建、版式调整到格式导出均可在浏览器端完成。").ApplyCharacterFormat(characterFormat);;
// 2.1 文档处理(二级标题)
p = section.AddParagraph();
p.AppendText("2.1 文档处理").ApplyCharacterFormat(characterFormat);;
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
section.AddParagraph().AppendText("支持段落、样式、表格、图片、页眉页脚等常见文档元素的创建与修改,并保留原有的版式信息。").ApplyCharacterFormat(characterFormat);;
// 2.1.1 段落与样式(三级标题)
p = section.AddParagraph();
p.AppendText("2.1.1 段落与样式").ApplyCharacterFormat(characterFormat);;
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading3 });
section.AddParagraph().AppendText("通过 AddParagraph 新增段落,配合 ApplyStyle 应用内置样式,即可快速搭建结构清晰的文档骨架。").ApplyCharacterFormat(characterFormat);;
// 2.1.2 表格与图片(三级标题)
p = section.AddParagraph();
p.AppendText("2.1.2 表格与图片").ApplyCharacterFormat(characterFormat);;
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading3 });
section.AddParagraph().AppendText("表格与图片既可以直接写入指定段落,也可以嵌套在文本框内,满足复杂版式的排版需求。").ApplyCharacterFormat(characterFormat);;
// 2.2 格式转换(二级标题)
p = section.AddParagraph();
p.AppendText("2.2 格式转换").ApplyCharacterFormat(characterFormat);;
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
section.AddParagraph().AppendText("通过 SaveToFile 可以将文档转换为 PDF、HTML、Markdown 等多种格式,整个转换过程均在浏览器端完成。").ApplyCharacterFormat(characterFormat);;
// 2.3 批量处理(二级标题)
p = section.AddParagraph();
p.AppendText("2.3 批量处理").ApplyCharacterFormat(characterFormat);;
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
section.AddParagraph().AppendText("结合 WebAssembly 的运行效率,可以一次加载多份文档并顺序完成处理,避免频繁的文件上传与下载。").ApplyCharacterFormat(characterFormat);;
// 第三章 快速上手(一级标题)
p = section.AddParagraph();
p.AppendText("第三章 快速上手").ApplyCharacterFormat(characterFormat);;
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading1 });
section.AddParagraph().AppendText("本章介绍在 React 项目中接入 Spire.Doc for JavaScript 并完成第一次文档生成所需的准备工作。").ApplyCharacterFormat(characterFormat);;
// 3.1 环境准备(二级标题)
p = section.AddParagraph();
p.AppendText("3.1 环境准备").ApplyCharacterFormat(characterFormat);;
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
section.AddParagraph().AppendText("在 React 项目中安装 Spire.Doc for JavaScript,并将字体文件与 WASM 资源放入 public 目录即可开始使用。").ApplyCharacterFormat(characterFormat);;
// 3.2 第一个示例(二级标题)
p = section.AddParagraph();
p.AppendText("3.2 第一个示例").ApplyCharacterFormat(characterFormat);;
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
section.AddParagraph().AppendText("初始化模块后创建 Document 实例,添加内容并保存,最后从 VFS 读取结果文件触发浏览器下载。").ApplyCharacterFormat(characterFormat);;
// 更新目录,填充条目与页码
doc.UpdateTableOfContents();
// 定义输出文件名并保存
const outputFileName = "在 Word 文档中创建默认目录.docx";
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
// 释放资源
doc.Dispose();
// 从 VFS 读取生成的文件,触发下载
const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([modifiedFileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>点击以下按钮在 Word 文档中创建默认目录</h1>
<button onClick={AddTableOfContentsToNewDocument}>
生成
</button>
</div>
);
}
export default App;
通过 AppendTOC 插入目录域并更新后,文档开头生成了收录三级标题、带页码与超链接的默认目录。

添加自定义目录
AppendTOC 生成的目录使用 Word 默认的域开关,当需要控制目录的具体行为时,可以改为直接构造 TableOfContent 对象并指定开关串。与上一个功能点的区别在于插入方式:需要手动将目录对象加入段落,并补齐域分隔符与域结束标记,同时将该对象赋给 document.TOC。常用的域开关及其含义如下:
| 开关 | 说明 |
|---|---|
\o "1-3" |
按内置标题样式收集条目,此处表示收录 Heading 1 至 Heading 3 |
\h |
将目录条目设为超链接,点击即可跳转到对应章节 |
\z |
在 Web 版式视图中隐藏页码与制表符前导符 |
\u |
按段落的大纲级别收集条目 |
例如将开关串改为 \o "1-2",目录就只收录一级和二级标题,三级标题不再出现在目录中;去掉 \h 则目录条目不再具备跳转能力。
function App() {
const CustomizeTableOfContent = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 确保 WASM 模块完全加载完成
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将字体载入 VFS
await window.spire.FetchFileToVFS('msyh.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 创建文档实例并添加节
const doc = new docModule.Document();
let section = doc.AddSection();
// 构造带自定义域开关的目录对象
let toc = new docModule.TableOfContent(doc, "{\\o \"1-2\" \\h \\z \\u}");
// 将目录对象加入段落
let tocPara = section.AddParagraph();
tocPara.Items.Add(toc);
// 补齐域分隔符与域结束标记
tocPara.AppendFieldMark(docModule.FieldMarkType.FieldSeparator);
tocPara.AppendText("TOC");
tocPara.AppendFieldMark(docModule.FieldMarkType.FieldEnd);
// 将该目录绑定到文档
doc.TOC = toc;
// 添加文档标题
let characterFormat = new docModule.CharacterFormat(doc);
characterFormat.FontName ="微软雅黑";
let title = section.AddParagraph();
let titleRun = title.AppendText("Spire.Doc 开发指南");
titleRun.ApplyCharacterFormat(characterFormat);
titleRun.CharacterFormat.FontSize = 24;
title.Format.HorizontalAlignment = docModule.HorizontalAlignment.Center;
// 第一章 概述(一级标题)
let p = section.AddParagraph();
p.AppendText("第一章 概述").ApplyCharacterFormat(characterFormat);
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading1 });
section.AddParagraph().AppendText("Spire.Doc for JavaScript 让开发者可以直接在浏览器中创建、编辑与保存 Word 文档,整个过程无需任何后端服务参与。").ApplyCharacterFormat(characterFormat);
// 1.1 什么是 Spire.Doc for JavaScript(二级标题)
p = section.AddParagraph();
p.AppendText("1.1 什么是 Spire.Doc for JavaScript").ApplyCharacterFormat(characterFormat);
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
section.AddParagraph().AppendText("它是一套基于 WebAssembly 的 Word 文档处理库,通过虚拟文件系统(VFS)管理字体与文档文件,并提供与 .NET 版一致的 API 形态。").ApplyCharacterFormat(characterFormat);
// 1.2 适用场景(二级标题)
p = section.AddParagraph();
p.AppendText("1.2 适用场景").ApplyCharacterFormat(characterFormat);
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
section.AddParagraph().AppendText("适用于在线合同签署、报表批量生成、简历模板填充等需要在客户端完成文档处理的场景。").ApplyCharacterFormat(characterFormat);
// 第二章 核心能力(一级标题)
p = section.AddParagraph();
p.AppendText("第二章 核心能力").ApplyCharacterFormat(characterFormat);
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading1 });
section.AddParagraph().AppendText("Spire.Doc for JavaScript 覆盖了文档处理的完整链路,从内容构建、版式调整到格式导出均可在浏览器端完成。").ApplyCharacterFormat(characterFormat);
// 2.1 文档处理(二级标题)
p = section.AddParagraph();
p.AppendText("2.1 文档处理").ApplyCharacterFormat(characterFormat);
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
section.AddParagraph().AppendText("支持段落、样式、表格、图片、页眉页脚等常见文档元素的创建与修改,并保留原有的版式信息。").ApplyCharacterFormat(characterFormat);
// 2.1.1 段落与样式(三级标题)
p = section.AddParagraph();
p.AppendText("2.1.1 段落与样式").ApplyCharacterFormat(characterFormat);
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading3 });
section.AddParagraph().AppendText("通过 AddParagraph 新增段落,配合 ApplyStyle 应用内置样式,即可快速搭建结构清晰的文档骨架。").ApplyCharacterFormat(characterFormat);
// 2.1.2 表格与图片(三级标题)
p = section.AddParagraph();
p.AppendText("2.1.2 表格与图片").ApplyCharacterFormat(characterFormat);
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading3 });
section.AddParagraph().AppendText("表格与图片既可以直接写入指定段落,也可以嵌套在文本框内,满足复杂版式的排版需求。").ApplyCharacterFormat(characterFormat);
// 2.2 格式转换(二级标题)
p = section.AddParagraph();
p.AppendText("2.2 格式转换").ApplyCharacterFormat(characterFormat);
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
section.AddParagraph().AppendText("通过 SaveToFile 可以将文档转换为 PDF、HTML、Markdown 等多种格式,整个转换过程均在浏览器端完成。").ApplyCharacterFormat(characterFormat);
// 2.3 批量处理(二级标题)
p = section.AddParagraph();
p.AppendText("2.3 批量处理").ApplyCharacterFormat(characterFormat);
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
section.AddParagraph().AppendText("结合 WebAssembly 的运行效率,可以一次加载多份文档并顺序完成处理,避免频繁的文件上传与下载。").ApplyCharacterFormat(characterFormat);
// 第三章 快速上手(一级标题)
p = section.AddParagraph();
p.AppendText("第三章 快速上手").ApplyCharacterFormat(characterFormat);
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading1 });
section.AddParagraph().AppendText("本章介绍在 React 项目中接入 Spire.Doc for JavaScript 并完成第一次文档生成所需的准备工作。").ApplyCharacterFormat(characterFormat);
// 3.1 环境准备(二级标题)
p = section.AddParagraph();
p.AppendText("3.1 环境准备").ApplyCharacterFormat(characterFormat);
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
section.AddParagraph().AppendText("在 React 项目中安装 Spire.Doc for JavaScript,并将字体文件与 WASM 资源放入 public 目录即可开始使用。").ApplyCharacterFormat(characterFormat);
// 3.2 第一个示例(二级标题)
p = section.AddParagraph();
p.AppendText("3.2 第一个示例").ApplyCharacterFormat(characterFormat);
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading2 });
section.AddParagraph().AppendText("初始化模块后创建 Document 实例,添加内容并保存,最后从 VFS 读取结果文件触发浏览器下载。").ApplyCharacterFormat(characterFormat);
// 更新目录,填充条目与页码
doc.UpdateTableOfContents();
// 定义输出文件名并保存
const outputFileName = "在 Word 文档中创建自定义目录.docx";
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
// 释放资源
doc.Dispose();
// 从 VFS 读取生成的文件,触发下载
const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([modifiedFileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>点击以下按钮在 Word 文档中创建自定义目录</h1>
<button onClick={CustomizeTableOfContent}>
生成
</button>
</div>
);
}
export default App;
通过 TableOfContent 对象与自定义域开关生成的目录,条目层级、超链接与页码表现均由开关串决定。

常见问题
生成的目录为空或没有任何条目
原因:目录域按标题样式收集条目。如果段落没有应用 Heading1 至 Heading3 等内置标题样式,即使成功插入了目录域,更新后目录中也不会出现任何条目。
解决:对需要出现在目录中的段落调用 ApplyStyle 应用标题样式:
p.AppendText("第一章 概述");
p.ApplyStyle({ builtinStyle: docModule.BuiltinStyle.Heading1 });
目录的条目层级比预期少
原因:AppendTOC 的两个参数分别对应目录收录的起始与结束标题级别,若传入 AppendTOC(1, 2),三级标题将不会出现在目录中。使用自定义开关时,\o "1-2" 也会产生同样的结果。
解决:按需要收录的层级调整参数范围,例如收录一至三级标题:
tocPara.AppendTOC(1, 3);
目录页码为空或与实际页码不一致
原因:AppendTOC 只是插入了目录域本身,域内容需要显式更新。若在保存前未调用 UpdateTableOfContents,生成的目录只有域代码,没有条目和页码。
解决:在 SaveToFile 之前调用更新方法:
doc.UpdateTableOfContents();
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。







