在 Web 应用开发中,合并 Word 文档是一个常见需求——将多份合同附件拼接成一份完整文档、在报告末尾追加补充内容、或者将多个章节的文档合并输出。Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端直接完成文档合并,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。
本文介绍两个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。以下示例默认已安装 Spire.Doc 并完成 WebAssembly 模块初始化。
以节为单位合并
以节为单位合并的核心流程分为三个阶段:首先通过 FetchFileToVFS 将字体文件和两个 Word 文档载入 WASM 虚拟文件系统;然后实例化 Document 加载目标文档和源文档,遍历源文档的所有节(Section),通过 Sections.Add(section.Clone()) 将每个节克隆并追加到目标文档末尾;最后从 VFS 读取合并后的文件,封装为 Blob 后触发浏览器下载。这种方式会保留源文档的独立分节结构,每个节在合并后文档中从新的一页开始。
function App() {
const mergeBySection = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
const inputFileName1 = 'Template_Docx_1.docx';
await window.spire.FetchFileToVFS(inputFileName1, '', `${process.env.PUBLIC_URL}data/`);
const inputFileName2 = 'Template_Docx_2.docx';
await window.spire.FetchFileToVFS(inputFileName2, '', `${process.env.PUBLIC_URL}data/`);
// 加载目标文档
const TarDoc = new docModule.Document();
TarDoc.LoadFromFile(inputFileName1);
// 加载源文档
const SouDoc = new docModule.Document();
SouDoc.LoadFromFile(inputFileName2);
// 将源文档的所有节克隆并追加到目标文档
for (let i = 0; i < SouDoc.Sections.Count; i++) {
let section = SouDoc.Sections.get_Item(i);
TarDoc.Sections.Add(section.Clone());
}
// 定义输出文件名
const outputFileName = 'MergeBySection_out.docx';
// 保存合并后的文档
TarDoc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
// 从 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);
// 释放资源
TarDoc.Dispose();
SouDoc.Dispose();
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Merge Word By Section</h1>
<button onClick={mergeBySection}>
Generate
</button>
</div>
);
}
export default App;
以节为单位合并后,源文档的每个节在目标文档中独立成页

同页合并
同页合并与以节合并不同,它不会为源文档创建新的节,而是将源文档中的段落、表格、图片等文档元素逐一克隆并追加到目标文档的同一个节中。核心流程同样分为三个阶段:首先通过 FetchFileToVFS 将字体文件和两个 Word 文档载入 WASM 虚拟文件系统;然后加载目标文档和源文档,通过双层循环遍历源文档每个节下的 Body.ChildObjects,将每个文档元素通过 ChildObjects.Add(obj.Clone()) 追加到目标文档第一个节的 ChildObjects 集合末尾;最后从 VFS 读取合并后的文件,封装为 Blob 后触发浏览器下载。这种方式使内容在页面上连续排列,不会产生新的分节符。
function App() {
const mergeOnSamePage = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
const inputFileName1 = 'Template_Docx_1.docx';
await window.spire.FetchFileToVFS(inputFileName1, '', `${process.env.PUBLIC_URL}data/`);
const inputFileName2 = 'Template_Docx_2.docx';
await window.spire.FetchFileToVFS(inputFileName2, '', `${process.env.PUBLIC_URL}data/`);
// 加载目标文档
const destinationDocument = new docModule.Document();
destinationDocument.LoadFromFile(inputFileName1);
let count = destinationDocument.Sections.Count;
// 加载源文档
const doc = new docModule.Document();
doc.LoadFromFile(inputFileName2);
// 遍历源文档的所有内容元素,克隆到目标文档的第一个节中
for (let i = 0; i < doc.Sections.Count; i++) {
let section = doc.Sections.get_Item(i);
for (let j = 0; j < section.Body.ChildObjects.Count; j++) {
let obj = section.Body.ChildObjects.get_Item(j);
destinationDocument.Sections.get_Item(count-1).Body.ChildObjects.Add(obj.Clone());
}
}
// 定义输出文件名
const outputFileName = 'MergeOnSamePage_out.docx';
// 保存合并后的文档
destinationDocument.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
// 从 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);
// 释放资源
destinationDocument.Dispose();
doc.Dispose();
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Merge On Same Page</h1>
<button onClick={mergeOnSamePage}>
Generate
</button>
</div>
);
}
export default App;
同页合并后,源文档的内容连续追加到目标文档同一节中,不产生分页

常见问题
合并后文档格式错乱
原因:源文档与目标文档的样式定义(如字体、字号、段落样式)不一致,合并后样式冲突导致显示异常。以节合并时,每个节保留自身的样式设置,而跨节的样式引用可能丢失。
解决:合并前通过 KeepSameFormat 属性保持源文档的原始格式:
srcDoc.KeepSameFormat = true;
合并后文档无法打开
原因:输出文件的 MIME 类型或文件扩展名错误,导致浏览器或 Word 无法正确识别文件格式。或者在保存文档后未正确释放资源,导致 VFS 文件句柄未释放。
解决:确保使用正确的 DOCX MIME 类型:
const blob = new Blob([data], {
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
});
同时确保在每次合并操作后调用 Dispose() 释放 Document 对象,避免 WASM 内存泄漏。
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。







