页眉和页脚是 Word 文档中不可或缺的组成部分——页眉通常用于放置公司 Logo、文档标题,页脚则用于显示页码、版权声明等辅助信息。Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端直接完成 Word 文档的创建与编辑,通过虚拟文件系统(VFS)管理字体和文件资源,无需后端服务支持。
本文介绍三个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。以下示例默认已安装 Spire.Doc 并完成 WebAssembly 模块初始化。
在实际开发中,最常遇到的需求是给文档添加页眉页脚:页眉中插入公司 Logo 和文档标题,页脚中插入页码和版权信息。Spire.Doc 通过 HeadersFooters.Header 和 HeadersFooters.Footer 获取页眉和页脚对象,然后使用 AppendPicture 插入图片、AppendText 插入文字、AppendField 插入页码字段。核心流程分为三个阶段:首先通过 FetchFileToVFS 将字体文件和目标 Word 文件载入 WASM 虚拟文件系统;然后实例化 Document 加载文件,获取节(Section)后调用自定义函数添加页眉页脚内容;最后将文档保存并从 VFS 读取生成的文件,封装为 Blob 后触发浏览器下载。
function InsertHeaderAndFooter(section, inputImgFileName, inputImgFileName_1) {
let wasmModule = window.wasmModule.spiredoc;
let header = section.HeadersFooters.Header;
let footer = section.HeadersFooters.Footer;
// 在页眉中插入图片和文字
let headerParagraph = header.AddParagraph();
let headerPicture = headerParagraph.AppendPicture({ imgFile: inputImgFileName });
// 页眉文字
let text = headerParagraph.AppendText("Demo of Spire.Doc");
text.CharacterFormat.FontName = "Arial";
text.CharacterFormat.FontSize = 10;
text.CharacterFormat.Italic = true;
headerParagraph.Format.HorizontalAlignment = wasmModule.HorizontalAlignment.Right;
// 页眉底部边框
headerParagraph.Format.Borders.Bottom.BorderType = wasmModule.BorderStyle.Single;
headerParagraph.Format.Borders.Bottom.Space = 0.05;
// 页眉图片布局 - 文字环绕
headerPicture.TextWrappingStyle = wasmModule.TextWrappingStyle.Behind;
// 页眉图片布局 - 位置
headerPicture.HorizontalOrigin = wasmModule.HorizontalOrigin.Page;
headerPicture.HorizontalAlignment = wasmModule.ShapeHorizontalAlignment.Left;
headerPicture.VerticalOrigin = wasmModule.VerticalOrigin.Page;
headerPicture.VerticalAlignment = wasmModule.ShapeVerticalAlignment.Top;
// 在页脚中插入图片
let footerParagraph = footer.AddParagraph();
let footerPicture = footerParagraph.AppendPicture({ imgFile: inputImgFileName_1 });
// 页脚图片布局
footerPicture.TextWrappingStyle = wasmModule.TextWrappingStyle.Behind;
footerPicture.HorizontalOrigin = wasmModule.HorizontalOrigin.Page;
footerPicture.HorizontalAlignment = wasmModule.ShapeHorizontalAlignment.Left;
footerPicture.VerticalOrigin = wasmModule.VerticalOrigin.Page;
footerPicture.VerticalAlignment = wasmModule.ShapeVerticalAlignment.Bottom;
// 插入页码
footerParagraph.AppendField("page number", wasmModule.FieldType.FieldPage);
footerParagraph.AppendText(" of ");
footerParagraph.AppendField("number of pages", wasmModule.FieldType.FieldNumPages);
footerParagraph.Format.HorizontalAlignment = wasmModule.HorizontalAlignment.Right;
// 页脚顶部边框
footerParagraph.Format.Borders.Top.BorderType = wasmModule.BorderStyle.Single;
footerParagraph.Format.Borders.Top.Space = 0.05;
}
function App() {
const AddHeaderAndFooter = async () => {
// 获取 Spire.Doc WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将示例 Word 文件载入 VFS
const inputFileName = "Sample.docx";
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
const inputImgFileName = "Header.png";
await window.spire.FetchFileToVFS(inputImgFileName, "", `${process.env.PUBLIC_URL}/data/`);
const inputImgFileName_1 = "Footer.png";
await window.spire.FetchFileToVFS(inputImgFileName_1, "", `${process.env.PUBLIC_URL}/data/`);
// 加载文档
let doc = new wasmModule.Document();
doc.LoadFromFile(inputFileName);
let section = doc.Sections.get_Item(0);
// 插入页眉和页脚
InsertHeaderAndFooter(section, inputImgFileName, inputImgFileName_1);
// 定义输出文件名
const outputFileName = "HeaderAndFooter.docx";
// 保存文档
doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.FileFormat.Docx2013 });
// 释放资源
doc.Close();
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={AddHeaderAndFooter}>
Generate
</button>
</div>
);
}
export default App;
生成的 Word 文档效果如下:

在实际开发中,很多文档的首页(封面页)需要使用与其他页面不同的页眉页脚,甚至不需要页眉页脚。Spire.Doc 通过设置 PageSetup.DifferentFirstPageHeaderFooter = true 来启用首页独立设置,然后分别通过 HeadersFooters.FirstPageHeader / FirstPageFooter 设置首页内容,通过 HeadersFooters.Header / Footer 设置其他页内容。
function App() {
const DifferentFirstPage = async () => {
// 获取 Spire.Doc WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将示例文件载入 VFS
let inputFileName = "MultiplePages.docx";
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
let inputImgFileName = "E-iceblue.png";
await window.spire.FetchFileToVFS(inputImgFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 加载文档
let doc = new wasmModule.Document();
doc.LoadFromFile(inputFileName);
// 获取节并启用首页独立页眉页脚
let section = doc.Sections.get_Item(0);
section.PageSetup.DifferentFirstPageHeaderFooter = true;
// 设置首页页眉:右侧插入图片
let paragraph1 = section.HeadersFooters.FirstPageHeader.AddParagraph();
paragraph1.Format.HorizontalAlignment = wasmModule.HorizontalAlignment.Right;
let headerimage = paragraph1.AppendPicture({ imgFile: inputImgFileName });
// 设置首页页脚:居中显示文字
let paragraph2 = section.HeadersFooters.FirstPageFooter.AddParagraph();
paragraph2.Format.HorizontalAlignment = wasmModule.HorizontalAlignment.Center;
let FF = paragraph2.AppendText("First Page Footer");
FF.CharacterFormat.FontSize = 10;
// 设置其他页的页眉和页脚
let paragraph3 = section.HeadersFooters.Header.AddParagraph();
paragraph3.Format.HorizontalAlignment = wasmModule.HorizontalAlignment.Center;
let NH = paragraph3.AppendText("Spire.Doc for JavaScript");
NH.CharacterFormat.FontSize = 10;
let paragraph4 = section.HeadersFooters.Footer.AddParagraph();
paragraph4.Format.HorizontalAlignment = wasmModule.HorizontalAlignment.Center;
let NF = paragraph4.AppendText("E-iceblue");
NF.CharacterFormat.FontSize = 10;
// 定义输出文件名
const outputFileName = "DifferentFirstPage.docx";
// 保存文档
doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.FileFormat.Docx2013 });
// 释放资源
doc.Close();
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>单击以下按钮以设置首页不同的页眉和页脚。</h1>
<button onClick={DifferentFirstPage}>
Generate
</button>
</div>
);
}
export default App;
首页显示单独的页眉页脚内容,而其他页使用统一的页眉页脚,生成的 Word 文档效果如下:

对于需要双面打印或书籍排版的文档,通常需要为奇偶页设置不同的页眉页脚——例如奇数页页眉显示章节名称并靠右对齐,偶数页页眉显示书名并靠左对齐。Spire.Doc 通过设置 PageSetup.DifferentOddAndEvenPagesHeaderFooter = true 来启用奇偶页独立设置,然后分别通过 OddHeader / OddFooter 和 EvenHeader / EvenFooter 设置各自的内容。
function App() {
const OddAndEvenHeaderFooter = async () => {
// 获取 Spire.Doc WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将示例文件载入 VFS
let inputFileName = "MultiplePages.docx";
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 加载文档
let doc = new wasmModule.Document();
doc.LoadFromFile(inputFileName);
// 获取第一个节
let section = doc.Sections.get_Item(0);
// 启用奇偶页不同的页眉页脚
section.PageSetup.DifferentOddAndEvenPagesHeaderFooter = true;
// 添加奇数页页眉
let P3 = section.HeadersFooters.OddHeader.AddParagraph();
let OH = P3.AppendText("Odd Header");
P3.Format.HorizontalAlignment = wasmModule.HorizontalAlignment.Center;
OH.CharacterFormat.FontName = "Arial";
OH.CharacterFormat.FontSize = 10;
// 添加偶数页页眉
let P4 = section.HeadersFooters.EvenHeader.AddParagraph();
let EH = P4.AppendText("Even Header from E-iceblue Using Spire.Doc");
P4.Format.HorizontalAlignment = wasmModule.HorizontalAlignment.Center;
EH.CharacterFormat.FontName = "Arial";
EH.CharacterFormat.FontSize = 10;
// 添加奇数页页脚
let P2 = section.HeadersFooters.OddFooter.AddParagraph();
let OF = P2.AppendText("Odd Footer");
P2.Format.HorizontalAlignment = wasmModule.HorizontalAlignment.Center;
OF.CharacterFormat.FontName = "Arial";
OF.CharacterFormat.FontSize = 10;
// 添加偶数页页脚
let P1 = section.HeadersFooters.EvenFooter.AddParagraph();
let EF = P1.AppendText("Even Footer from E-iceblue Using Spire.Doc");
EF.CharacterFormat.FontName = "Arial";
EF.CharacterFormat.FontSize = 10;
P1.Format.HorizontalAlignment = wasmModule.HorizontalAlignment.Center;
// 定义输出文件名
const outputFileName = "OddAndEvenHeaderFooter_output.docx";
// 保存文档
doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.FileFormat.Docx2013 });
// 释放资源
doc.Close();
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>单击以下按钮以设置奇偶页不同的页眉和页脚。</h1>
<button onClick={OddAndEvenHeaderFooter}>
Generate
</button>
</div>
);
}
export default App;
奇偶页分别设置了不同的页眉和页脚文字,生成的 Word 文档效果如下:

原因:DifferentFirstPageHeaderFooter 属性默认为 false,直接编辑 FirstPageHeader 或 FirstPageFooter 不会生效。
解决:编辑首页页眉页脚前先设置该属性为 true:
section.PageSetup.DifferentFirstPageHeaderFooter = true;
// 然后再编辑 FirstPageHeader / FirstPageFooter
原因:DifferentOddAndEvenPagesHeaderFooter 属性默认为 false,直接编辑 OddHeader / EvenHeader 不会生效。
解决:启用该属性后再编辑奇偶页内容:
section.PageSetup.DifferentOddAndEvenPagesHeaderFooter = true;
// 然后再编辑 OddHeader / EvenHeader / OddFooter / EvenFooter
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
在日常的 Word 文档开发中,合并与拆分表格单元格是最常见的表格编辑操作之一。无论是制作带有跨列标题的报表表头,还是实现跨行合并的产品分组展示,单元格合并都能让表格结构更加清晰合理。Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端直接完成 Word 文档的创建与编辑,通过虚拟文件系统(VFS)管理字体和文件资源,无需后端服务支持。
本文介绍三个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。以下示例默认已安装 Spire.Doc 并完成 WebAssembly 模块初始化。
在实际开发中,最常遇到的需求是对已有表格进行结构调整:将多个相邻的单元格合并为一个,或者将一个单元格拆分为多行多列。Spire.Doc 提供了 ApplyHorizontalMerge、ApplyVerticalMerge 和 SplitCell 三个方法分别实现水平合并、垂直合并和拆分操作。核心流程分为三个阶段:首先通过 FetchFileToVFS 将字体文件和目标 Word 文件载入 WASM 虚拟文件系统;然后实例化 Document 加载文件,获取目标表格后调用合并与拆分方法;最后将文档保存并从 VFS 读取生成的文件,封装为 Blob 后触发浏览器下载。
function App() {
const MergeAndSplitTableCell = async () => {
// 获取 Spire.Doc WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将示例 Word 文件载入 VFS
let inputFileName = "TableSample.docx";
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 加载文档
let doc = new wasmModule.Document();
doc.LoadFromFile(inputFileName);
let section = doc.Sections.get_Item(0);
let table = section.Tables.get_Item(0);
// 水平合并:将第 6 行的第 2、3 列合并
table.ApplyHorizontalMerge(6, 2, 3);
// 垂直合并:将第 2 列的第 4、5 行合并
table.ApplyVerticalMerge(2, 4, 5);
// 拆分单元格:将第 8 行第 3 列的单元格拆分为 2 行 2 列
table.Rows.get_Item(8).Cells.get_Item(3).SplitCell(2, 2);
// 定义输出文件名
const outputFileName = "MergeAndSplitTableCell_output.docx";
// 保存文档
doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.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={MergeAndSplitTableCell}>
Generate
</button>
</div>
);
}
export default App;
生成的 Word 文档效果如下:

合并单元格后,通常还需要对合并后的区域进行格式化,例如设置字体样式、对齐方式和背景色,以提升表格的可读性和美观度。下面的示例演示了如何创建一个产品价格表,合并表头"Product"单元格和左侧的版本类别单元格,并对其应用自定义样式。
function AddTable(section) {
let wasmModule = window.wasmModule.spiredoc;
let table = section.AddTable({ showBorder: true });
table.ResetCells(4, 3);
// 表格数据
let dt = [["产品", "", "库存(kg)"],
["水果", "苹果", "150"],
["", "葡萄", "200"],
["", "柠檬", "100"]];
for (let r = 0; r < dt.length; r++) {
let dataRow = table.Rows.get_Item(r);
dataRow.Height = 20;
dataRow.HeightType = wasmModule.TableRowHeightType.Exactly;
for (let i = 0; i < dataRow.Cells.Count; i++) {
dataRow.Cells.get_Item(i).CellFormat.Shading.BackgroundPatternColor = wasmModule.Color.Empty;
}
for (let c = 0; c < dataRow.Cells.Count; c++) {
if (dt[r][c] !== "") {
let range = dataRow.Cells.get_Item(c).AddParagraph().AppendText(dt[r][c]);
range.CharacterFormat.FontName = "Arial";
}
}
}
return table;
}
function App() {
const FormatMergedCells = async () => {
// 获取 Spire.Doc WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将字体和文档文件载入 VFS
await window.spire.FetchFileToVFS('msyh.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 创建 Word 文档
let doc = new wasmModule.Document();
let section = doc.AddSection();
// 添加表格
let table = AddTable(section);
// 创建自定义样式
let style = new wasmModule.ParagraphStyle(doc);
style.Name = "Style";
style.CharacterFormat.TextColor = wasmModule.Color.get_DeepSkyBlue();
style.CharacterFormat.Italic = true;
style.CharacterFormat.Bold = true;
style.CharacterFormat.FontSize = 13;
doc.Styles.Add(style);
// 水平合并:将第一行的第 0、1 列合并
table.ApplyHorizontalMerge(0, 0, 1);
// 应用样式
table.Rows.get_Item(0).Cells.get_Item(0).Paragraphs.get_Item(0).ApplyStyle(style.Name);
// 设置垂直和水平对齐
table.Rows.get_Item(0).Cells.get_Item(0).CellFormat.VerticalAlignment = wasmModule.VerticalAlignment.Middle;
table.Rows.get_Item(0).Cells.get_Item(0).Paragraphs.get_Item(0).Format.HorizontalAlignment = wasmModule.HorizontalAlignment.Center;
// 垂直合并:将第 0 列的第 1、2、3 行合并
table.ApplyVerticalMerge(0, 1, 3);
// 应用样式
table.Rows.get_Item(1).Cells.get_Item(0).Paragraphs.get_Item(0).ApplyStyle(style.Name);
// 设置垂直和水平对齐
table.Rows.get_Item(1).Cells.get_Item(0).CellFormat.VerticalAlignment = wasmModule.VerticalAlignment.Middle;
table.Rows.get_Item(1).Cells.get_Item(0).Paragraphs.get_Item(0).Format.HorizontalAlignment = wasmModule.HorizontalAlignment.Left;
// 设置列宽占比
table.Rows.get_Item(1).Cells.get_Item(0).SetCellWidth(20, wasmModule.CellWidthType.Percentage);
// 定义输出文件名
const outputFileName = "FormatMergedCells_output.docx";
// 保存文档
doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.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>单击以下按钮以格式化合并的单元格。</h1>
<button onClick={FormatMergedCells}>
Generate
</button>
</div>
);
}
export default App;
生成的 Word 文档效果如下:

在处理他人创建的文档或自动化流程生成的表格时,常常需要先了解哪些单元格已被合并,以避免操作索引越界。Spire.Doc 通过 CellFormat.VerticalMerge 和 Cell.GridSpan 两个属性来检测单元格的合并状态:VerticalMerge 指示垂直合并情况,GridSpan 表示水平合并跨越的列数。
function App() {
const CellMergeStatus = async () => {
// 获取 Spire.Doc WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将示例文件载入 VFS
let inputFileName = "CellMergeStatus.docx";
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 加载文档
let doc = new wasmModule.Document();
doc.LoadFromFile(inputFileName);
// 获取第一个节和第一个表格
let section = doc.Sections.get_Item(0);
let table = section.Tables.get_Item(0);
// 遍历所有单元格,检测合并状态
let stringBuidler = [];
for (let i = 0; i < table.Rows.Count; i++) {
let tableRow = table.Rows.get_Item(i);
for (let j = 0; j < tableRow.Cells.Count; j++) {
let tableCell = tableRow.Cells.get_Item(j);
let verticalMerge = tableCell.CellFormat.VerticalMerge;
let horizontalMerge = tableCell.GridSpan;
if (verticalMerge === wasmModule.CellMerge.None && horizontalMerge === 1) {
stringBuidler.push("Row " + i + ", cell " + j + ": ");
stringBuidler.push("This cell isn't merged.\n");
} else {
stringBuidler.push("Row " + i + ", cell " + j + ": ");
stringBuidler.push("This cell is merged.\n");
}
}
stringBuidler.push("\n");
}
// 定义输出文件名
const outputFileName = "CellMergeStatus_output.txt";
// 将检测结果写入文本文件
window.dotnetRuntime.Module.FS.writeFile(outputFileName, stringBuidler.join('\n'));
// 从 VFS 读取生成的文件,触发下载
const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([modifiedFileArray], { type: "text/plain" });
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={CellMergeStatus}>
Generate
</button>
</div>
);
}
export default App;
检测结果以文本文件输出:

原因:合并操作本身不返回状态值,需要通过读取单元格属性来确认。
解决:使用 CellFormat.VerticalMerge 判断垂直合并类型(CellMerge.None 表示未合并),使用 Cell.GridSpan 判断水平合并跨越的列数(值为 1 表示未合并):
let verticalMerge = tableCell.CellFormat.VerticalMerge;
let horizontalMerge = tableCell.GridSpan;
if (verticalMerge === wasmModule.CellMerge.None && horizontalMerge === 1) {
// 未合并
} else {
// 已合并
}
原因:SplitCell 方法将单元格拆分为多个子单元格后,原有内容默认保留在第一个子单元格中。
解决:拆分后手动遍历子单元格重新分配内容,或拆分前通过 Paragraphs 集合备份单元格文本:
// 备份内容
let cell = table.Rows.get_Item(row).Cells.get_Item(col);
let text = cell.Paragraphs.get_Item(0).Text;
// 拆分为 2 行 2 列
cell.SplitCell(2, 2);
// 将内容写入新的单元格
table.Rows.get_Item(row).Cells.get_Item(col).Paragraphs.get_Item(0).AppendText(text);
原因:ApplyHorizontalMerge(row, startCol, endCol) 和 ApplyVerticalMerge(col, startRow, endRow) 的索引从 0 开始,传入的索引超出表格的实际行列数会引发错误。
解决:合并前检查表格的行列数,确保结束索引不超过 Rows.Count - 1 和 Cells.Count - 1:
if (endCol < table.Rows.get_Item(row).Cells.Count && endRow < table.Rows.Count) {
table.ApplyHorizontalMerge(row, startCol, endCol);
}
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
在实际的文档开发流程中,页眉页脚的维护操作与添加同样重要——从模板文档复制页眉页脚到新文档实现快速复用、移除旧页眉页脚进行文档清理、锁定页眉防止内容被篡改,这些都是日常工作中频繁遇到的需求。Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端直接完成 Word 文档的处理,通过虚拟文件系统(VFS)管理字体和文件资源,无需后端服务支持。
本文介绍三个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。以下示例默认已安装 Spire.Doc 并完成 WebAssembly 模块初始化。
在企业文档生产中,通常有一个标准模板文档定义了统一的页眉(公司 Logo + 文档标题)和页脚(页码 + 版权声明)。当创建新文档时,需要将模板中的页眉页脚复制过来,以保持企业文档风格的一致性。Spire.Doc 通过 ChildObjects 集合和 Clone 方法实现页眉对象的跨文档复制。核心流程分为三个阶段:首先通过 FetchFileToVFS 将字体文件和两个 Word 文件(源文档和目标文档)载入 WASM 虚拟文件系统;然后分别实例化两个 Document,从源文档获取页眉的子对象集合,遍历并克隆到目标文档各节的页眉中;最后将目标文档保存并从 VFS 读取生成的文件,封装为 Blob 后触发浏览器下载。
function App() {
const CopyHeaderAndFooter = async () => {
// 获取 Spire.Doc WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将源文件和目标文件载入 VFS
let inputFileName = "HeaderAndFooter.docx";
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
const inputFileName_1 = "Template.docx";
await window.spire.FetchFileToVFS(inputFileName_1, "", `${process.env.PUBLIC_URL}/data/`);
// 加载源文档
let doc1 = new wasmModule.Document();
doc1.LoadFromFile(inputFileName);
// 获取源文档的页眉
let header = doc1.Sections.get_Item(0).HeadersFooters.Header;
// 加载目标文档
let doc2 = new wasmModule.Document();
doc2.LoadFromFile(inputFileName_1);
// 将源文档页眉中的每个子对象克隆到目标文档的所有节
for (let i = 0; i < doc2.Sections.Count; i++) {
let section = doc2.Sections.get_Item(i);
for (let j = 0; j < header.ChildObjects.Count; j++) {
let obj = header.ChildObjects.get_Item(j);
section.HeadersFooters.Header.ChildObjects.Add(obj.Clone());
}
}
// 定义输出文件名
const outputFileName = "CopyHeaderAndFooter_output.docx";
// 保存文档
doc2.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.FileFormat.Docx2013 });
// 释放资源
doc1.Close();
doc2.Close();
doc1.Dispose();
doc2.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={CopyHeaderAndFooter}>
Generate
</button>
</div>
);
}
export default App;
上述代码将源文档中已有的页眉内容克隆到目标文档的所有节中,生成的 Word 文档效果如下:

在文档清理或模板替换场景中,经常需要移除文档中现有的页眉或页脚。例如:接手他人文档需要重新设计页眉页脚时,先清空原有内容;或者从客户系统导出的文档包含默认页眉,需要移除后替换为企业模板。Spire.Doc 通过 HeadersFooters.get_Item 按类型获取首页、奇数页、偶数页的页眉或页脚对象,然后调用 ChildObjects.Clear() 清除其所有内容。
function App() {
const RemoveHeaderFooter = async () => {
// 获取 Spire.Doc WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将示例文件载入 VFS
let inputFileName = "HeaderAndFooter.docx";
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 加载文档
let doc = new wasmModule.Document();
doc.LoadFromFile(inputFileName);
// 获取第一个节
let section = doc.Sections.get_Item(0);
// 清除所有类型的页眉内容(首页、奇数页、偶数页)
let header;
header = section.HeadersFooters.get_Item({ hfType: wasmModule.HeaderFooterType.HeaderFirstPage });
if (header != null)
header.ChildObjects.Clear();
header = section.HeadersFooters.get_Item({ hfType: wasmModule.HeaderFooterType.HeaderOdd });
if (header != null)
header.ChildObjects.Clear();
header = section.HeadersFooters.get_Item({ hfType: wasmModule.HeaderFooterType.HeaderEven });
if (header != null)
header.ChildObjects.Clear();
// 清除所有类型的页脚内容(首页、奇数页、偶数页)
let footer;
footer = section.HeadersFooters.get_Item({ hfType: wasmModule.HeaderFooterType.FooterFirstPage });
if (footer != null)
footer.ChildObjects.Clear();
footer = section.HeadersFooters.get_Item({ hfType: wasmModule.HeaderFooterType.FooterOdd });
if (footer != null)
footer.ChildObjects.Clear();
footer = section.HeadersFooters.get_Item({ hfType: wasmModule.HeaderFooterType.FooterEven });
if (footer != null)
footer.ChildObjects.Clear();
// 定义输出文件名
const outputFileName = "RemoveHeaderFooter_output.docx";
// 保存文档
doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.FileFormat.Docx2013 });
// 释放资源
doc.Close();
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={RemoveHeaderFooter}>
Generate
</button>
</div>
);
}
export default App;
移除页眉后的文档效果如下:

在将文档分发给客户或团队成员时,通常希望页眉中的公司 Logo、文档编号等固定信息不被修改,同时允许正文区域正常编辑。Spire.Doc 通过文档保护功能实现这一点:将保护类型设置为 AllowOnlyFormFields,然后将节的 ProtectForm 属性设为 false,这样正文区域保持可编辑状态,而页眉区域则受到保护不可修改。
function App() {
const LockHeader = async () => {
// 获取 Spire.Doc WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将示例文件载入 VFS
let inputFileName = "HeaderAndFooter.docx";
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 加载文档
let doc = new wasmModule.Document();
doc.LoadFromFile(inputFileName);
// 获取第一个节
let section = doc.Sections.get_Item(0);
// 保护文档,设置保护类型为 AllowOnlyFormFields
doc.Protect({ type: wasmModule.ProtectionType.AllowOnlyFormFields, password: "123" });
// 将节设置为可编辑,使正文区域不被锁定
section.ProtectForm = false;
// 定义输出文件名
const outputFileName = "LockHeader_output.docx";
// 保存文档
doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.FileFormat.Docx2013 });
// 释放资源
doc.Close();
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={LockHeader}>
Generate
</button>
</div>
);
}
export default App;
页眉被锁定后,在 Word 中打开文档时页眉区域不可编辑,而正文区域可以正常修改,生成的 Word 文档效果如下:

原因:目标文档包含多个节(Section),但复制操作只处理了第一节的页眉,其他节的页眉未被更新。
解决:遍历目标文档的所有节,将源页眉内容复制到每一节:
for (let i = 0; i < doc2.Sections.Count; i++) {
let section = doc2.Sections.get_Item(i);
for (let j = 0; j < header.ChildObjects.Count; j++) {
let obj = header.ChildObjects.get_Item(j);
section.HeadersFooters.Header.ChildObjects.Add(obj.Clone());
}
}
原因:doc.Protect({ type: AllowOnlyFormFields }) 默认会锁定整个文档,包括正文区域。
解决:设置保护后,将节的 ProtectForm 属性设为 false,使正文区域保持可编辑状态:
doc.Protect({ type: wasmModule.ProtectionType.AllowOnlyFormFields, password: "123" });
section.ProtectForm = false;
原因:误将移除页眉的代码逻辑应用到页脚,或者使用了相同的 ChildObjects.Clear() 操作作用于了错误的对象。
解决:移除页眉和移除页脚使用不同的 HeaderFooterType 参数,确保操作的对象是正确的:
// 移除页眉时使用 Header 类型
section.HeadersFooters.get_Item({ hfType: wasmModule.HeaderFooterType.HeaderFirstPage });
// 移除页脚时使用 Footer 类型
section.HeadersFooters.get_Item({ hfType: wasmModule.HeaderFooterType.FooterFirstPage });
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
在实际的文档开发中,表格的结构往往需要根据数据动态调整——报表数据行数不确定时需要动态添加行,字段调整时需要新增或移除列,冗余数据行需要一键删除。Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端直接完成 Word 文档的编辑,通过虚拟文件系统(VFS)管理字体和文件资源,无需后端服务支持。
本文介绍两个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。以下示例默认已安装 Spire.Doc 并完成 WebAssembly 模块初始化。
在报表生成和数据展示场景中,表格的行数通常是动态变化的。Spire.Doc 提供了 Rows.RemoveAt 方法删除指定行,Rows.Insert 方法在指定位置插入新行,以及 AddRow 方法在表格末尾追加行。核心流程分为三个阶段:首先通过 FetchFileToVFS 将字体文件和目标 Word 文件载入 WASM 虚拟文件系统;然后实例化 Document 加载文件,获取目标表格后调用行列操作方法;最后将文档保存并从 VFS 读取生成的文件,封装为 Blob 后触发浏览器下载。
function App() {
const AddOrDeleteRow = async () => {
// 获取 Spire.Doc WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将字体和文档文件载入 VFS
await window.spire.FetchFileToVFS('msyh.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 将示例 Word 文件载入 VFS
let inputFileName = "TableSample.docx";
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 加载文档
let doc = new wasmModule.Document();
doc.LoadFromFile(inputFileName);
let section = doc.Sections.get_Item(0);
let table = section.Tables.get_Item(0);
// 删除第 8 行
table.Rows.RemoveAt(7);
// 创建一个新行并插入到指定位置(第 2 行之后)
let row = new wasmModule.TableRow(doc);
for (let i = 0; i < table.Rows.get_Item(0).Cells.Count; i++) {
let tc = row.AddCell();
let paragraph = tc.AddParagraph();
paragraph.Format.HorizontalAlignment = wasmModule.HorizontalAlignment.Center;
paragraph.AppendText("Added");
}
table.Rows.Insert(2, row);
// 在表格末尾追加一行
table.AddRow();
// 定义输出文件名
const outputFileName = "AddOrDeleteRow_output.docx";
// 保存文档
doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.FileFormat.Docx2013 });
// 释放资源
doc.Close();
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={AddOrDeleteRow}>
Generate
</button>
</div>
);
}
export default App;
上述代码在已有表格上执行了三种行操作:删除第 8 行、在第 2 行之后插入一个包含 "Added" 文字的新行、在表格末尾追加一个空行,生成的 Word 文档效果如下:

在表格结构调整场景中,经常需要新增字段列或移除冗余列。由于 Spire.Doc 的表格列操作是通过逐行操作单元格来实现的,因此需要自定义 AddColumn 和 RemoveColumn 辅助函数:添加列时遍历每一行并在指定索引处插入一个新的空白单元格;删除列时遍历每一行并移除指定索引处的单元格。
function AddColumn(table, columnIndex) {
let wasmModule = window.wasmModule.spiredoc;
for (let r = 0; r < table.Rows.Count; r++) {
let addCell = new wasmModule.TableCell(table.Document);
table.Rows.get_Item(r).Cells.Insert(columnIndex, addCell);
}
}
function RemoveColumn(table, columnIndex) {
for (let r = 0; r < table.Rows.Count; r++) {
table.Rows.get_Item(r).Cells.RemoveAt(columnIndex);
}
}
function App() {
const AddOrRemoveColumn = async () => {
// 获取 Spire.Doc WASM 模块
const wasmModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!wasmModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将示例文件载入 VFS
let inputFileName = "TableSample.docx";
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 加载文档
let doc = new wasmModule.Document();
doc.LoadFromFile(inputFileName);
// 获取第一个节和第一个表格
let section = doc.Sections.get_Item(0);
let table = section.Tables.get_Item(0);
// 在第 0 列之前添加一个空白列
let columnIndex1 = 0;
AddColumn(table, columnIndex1);
// 删除第 2 列
let columnIndex2 = 2;
RemoveColumn(table, columnIndex2);
// 定义输出文件名
const outputFileName = "AddOrRemoveColumn_output.docx";
// 保存文档
doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.FileFormat.Docx2013 });
// 释放资源
doc.Close();
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={AddOrRemoveColumn}>
Generate
</button>
</div>
);
}
export default App;
上述代码在表格第 0 列插入了一个空白列,同时删除了第 2 列,生成的 Word 文档效果如下:

原因:表格中存在合并单元格时,直接按索引删除行会导致后续行的索引偏移,破坏合并结构。
解决:删除前检查目标行是否参与了合并。如果行中有合并单元格,可先解除合并再执行删除操作:
// 删除前检查单元格的合并状态
let cell = table.Rows.get_Item(rowIndex).Cells.get_Item(0);
let verticalMerge = cell.CellFormat.VerticalMerge;
if (verticalMerge === wasmModule.CellMerge.None) {
table.Rows.RemoveAt(rowIndex);
} else {
console.warn("该行包含合并单元格,建议先处理合并状态");
}
原因:AddColumn 函数仅插入了空白 TableCell 对象,未向新单元格中添加段落和文字内容。
解决:插入单元格后,遍历新列并添加段落和文字:
function AddColumn(table, columnIndex) {
let wasmModule = window.wasmModule.spiredoc;
for (let r = 0; r < table.Rows.Count; r++) {
let addCell = new wasmModule.TableCell(table.Document);
let paragraph = addCell.AddParagraph();
paragraph.AppendText("New Column");
table.Rows.get_Item(r).Cells.Insert(columnIndex, addCell);
}
}
原因:传入的列索引超过了当前表格的最大列数,或者表格各行的列数不一致。
解决:删除前获取表格第一行的列数作为参考,确保索引不超出范围:
let maxColIndex = table.Rows.get_Item(0).Cells.Count - 1;
if (columnIndex <= maxColIndex) {
RemoveColumn(table, columnIndex);
}
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
在 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 天的临时许可证。
表格是 Word 文档中组织和展示数据的核心元素,合理的表格排版直接影响文档的可读性与专业性。Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端直接完成表格的自动调整操作,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。
本文介绍三个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。以下示例默认已安装 Spire.Doc 并完成 WebAssembly 模块初始化。
根据内容自动调整表格的核心流程分为三个阶段:首先通过 FetchFileToVFS 将字体文件和目标文档载入 WASM 虚拟文件系统;然后实例化 Document 加载文档,获取目标表格后调用 AutoFit 方法并传入 AutoFitToContents 参数;最后保存文档并从 VFS 读取生成的文件,封装为 Blob 后触发浏览器下载。
function App() {
const autoFitToContents = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
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 inputFileName = 'TableSample.docx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);
// 加载文档
const doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// 获取第一个节中的第一个表格
let section = doc.Sections.get_Item(0);
let table = section.Tables.get_Item(0);
// 根据单元格内容自动调整列宽
table.AutoFit(docModule.AutoFitBehaviorType.AutoFitToContents);
// 定义输出文件名
const outputFileName = "AutoFitToContents_output.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>自动适应内容。</h1>
<button onClick={autoFitToContents}>
Generate
</button>
</div>
);
}
export default App;
通过 AutoFitToContents 模式调整后,表格各列的宽度会根据单元格内实际内容的长度自动收缩,使表格紧凑且无多余空白。

根据窗口自动调整表格可以让表格宽度自适应页面宽度,适合需要表格撑满页面宽度的场景。
function App() {
const autoFitToWindow = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
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 inputFileName = 'TableSample.docx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);
// 加载文档
const doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// 获取第一个节中的第一个表格
let section = doc.Sections.get_Item(0);
let table = section.Tables.get_Item(0);
// 根据页面宽度自动调整表格
table.AutoFit(docModule.AutoFitBehaviorType.AutoFitToWindow);
// 定义输出文件名
const outputFileName = "AutoFitToWindow_output.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>自动适应窗口。</h1>
<button onClick={autoFitToWindow}>
Generate
</button>
</div>
);
}
export default App;
通过 AutoFitToWindow 模式调整后,表格宽度会扩展至与页面宽度一致,各列按比例均匀分布。

当表格已有精心设计的列宽,不希望因内容增减而发生变化时,可以使用固定列宽模式,禁止 Word 自动调整列的大小。
function App() {
const fixedColumnWidths = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
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 inputFileName = 'TableSample.docx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);
// 加载文档
const doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// 获取第一个节中的第一个表格
let section = doc.Sections.get_Item(0);
let table = section.Tables.get_Item(0);
// 固定表格列宽,禁止自动调整
table.AutoFit(docModule.AutoFitBehaviorType.FixedColumnWidths);
// 定义输出文件名
const outputFileName = "FixedColumnWidths_output.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>固定列宽。</h1>
<button onClick={fixedColumnWidths}>
Generate
</button>
</div>
);
}
export default App;
使用固定列宽模式后,无论单元格内容如何变化,表格的列宽都会保持原有尺寸,确保排版的一致性。

原因:调用 AutoFit 方法时传入的参数类型不正确,或者表格被锁定不允许调整布局。
解决:确保使用正确的 AutoFitBehaviorType 枚举值:
// 根据内容调整
table.AutoFit(docModule.AutoFitBehaviorType.AutoFitToContents);
// 根据窗口调整
table.AutoFit(docModule.AutoFitBehaviorType.AutoFitToWindow);
// 固定列宽
table.AutoFit(docModule.AutoFitBehaviorType.FixedColumnWidths);
原因:文档中不存在指定索引的节或表格,通常是因为索引从 0 开始但文档中实际没有对应的对象。
解决:先检查节和表格的数量,再访问对应索引:
if (document.Sections.Count > 0 && document.Sections.get_Item(0).Tables.Count > 0) {
let section = document.Sections.get_Item(0);
let table = section.Tables.get_Item(0);
table.AutoFit(docModule.AutoFitBehaviorType.AutoFitToContents);
}
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
在 Word 文档中创建表格是日常办公开发中最常见的需求之一,无论是数据报表、产品清单还是统计分析,表格都能以结构化的方式清晰呈现信息。Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端直接完成 Word 文档的创建与编辑,通过虚拟文件系统(VFS)管理字体和文件资源,无需后端服务支持。
本文介绍三个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。以下示例默认已安装 Spire.Doc 并完成 WebAssembly 模块初始化。
在实际开发中,最常见的场景是将后端返回的数据以表格形式写入 Word 文档。核心流程分为三个阶段:首先通过 FetchFileToVFS 将字体文件载入 WASM 虚拟文件系统;然后实例化 Document 创建文档,通过 AddTable 添加表格并填充数据,设置表头、对齐方式、交替行颜色等格式;最后将文档保存并从 VFS 读取生成的文件,封装为 Blob 后触发浏览器下载。
function addTable(section) {
let docModule = window.wasmModule.spiredoc;
let header = ["名称", "首都", "大洲", "面积", "人口"];
let data =
[
["阿根廷", "布宜诺斯艾利斯", "南美洲", "2777815", "32300003"],
["玻利维亚", "拉巴斯", "南美洲", "1098575", "7300000"],
["巴西", "巴西利亚", "南美洲", "8511196", "150400000"],
["加拿大", "渥太华", "北美洲", "9976147", "26500000"],
["智利", "圣地亚哥", "南美洲", "756943", "13200000"],
["哥伦比亚", "波哥大", "南美洲", "1138907", "33000000"],
["古巴", "哈瓦那", "北美洲", "114524", "10600000"],
["厄瓜多尔", "基多", "南美洲", "455502", "10600000"],
["萨尔瓦多", "圣萨尔瓦多", "北美洲", "20865", "5300000"],
["圭亚那", "乔治敦", "南美洲", "214969", "800000"],
["牙买加", "金斯敦", "北美洲", "11424", "2500000"],
["墨西哥", "墨西哥城", "北美洲", "1967180", "88600000"],
["尼加拉瓜", "马那瓜", "北美洲", "139000", "3900000"],
["巴拉圭", "亚松森", "南美洲", "406576", "4660000"],
["秘鲁", "利马", "南美洲", "1285215", "21600000"],
["美利坚合众国", "华盛顿", "北美洲", "9363130", "249200000"],
["乌拉圭", "蒙得维的亚", "南美洲", "176140", "3002000"],
["委内瑞拉", "加拉加斯", "南美洲", "912047", "19700000"]
];
let table = section.AddTable({ showBorder: true });
table.ResetCells(data.length + 1, header.length);
// 设置表头行
let row = table.Rows.get_Item(0);
row.IsHeader = true;
row.Height = 20;
row.HeightType = docModule.TableRowHeightType.Exactly;
for (let i = 0; i < row.Cells.Count; i++) {
row.Cells.get_Item(i).CellFormat.Shading.BackgroundPatternColor = docModule.Color.get_Gray();
}
for (let i = 0; i < header.length; i++) {
row.Cells.get_Item(i).CellFormat.VerticalAlignment = docModule.VerticalAlignment.Middle;
let p = row.Cells.get_Item(i).AddParagraph();
p.Format.HorizontalAlignment = docModule.HorizontalAlignment.Center;
let txtRange = p.AppendText(header[i]);
txtRange.CharacterFormat.Bold = true;
}
// 填充数据行并设置交替行颜色
for (let r = 0; r < data.length; r++) {
let dataRow = table.Rows.get_Item(r + 1);
dataRow.Height = 20;
dataRow.HeightType = docModule.TableRowHeightType.Exactly;
for (let i = 0; i < dataRow.Cells.Count; i++) {
dataRow.Cells.get_Item(i).CellFormat.Shading.BackgroundPatternColor = docModule.Color.Empty();
}
for (let c = 0; c < data[r].length; c++) {
dataRow.Cells.get_Item(c).CellFormat.VerticalAlignment = docModule.VerticalAlignment.Middle;
dataRow.Cells.get_Item(c).AddParagraph().AppendText(data[r][c]);
}
}
// 偶数行设置浅蓝色背景
for (let j = 1; j < table.Rows.Count; j++) {
if (j % 2 == 0) {
let row2 = table.Rows.get_Item(j);
for (let f = 0; f < row2.Cells.Count; f++) {
row2.Cells.get_Item(f).CellFormat.Shading.BackgroundPatternColor = docModule.Color.get_LightBlue();
}
}
}
}
function App() {
const CreateTable = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将字体和文档文件载入 VFS
await window.spire.FetchFileToVFS('ARIALUNI.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 创建空白文档
let doc = new docModule.Document();
let section = doc.AddSection();
// 添加表格
addTable(section);
// 定义输出文件名
const outputFileName = "CreateTable_output.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={CreateTable}>
Generate
</button>
</div>
);
}
export default App;
上述代码创建了一个包含 18 行国家数据的表格,表头使用灰色背景和加粗字体居中对齐,数据区域使用交替行颜色(偶数行浅蓝背景)提升可读性,生成的 Word 文档效果如下:

在 Web 开发中,HTML 表格是展示数据的通用格式。Spire.Doc 提供了 AppendHTML 方法,可以直接将 HTML 字符串解析为 Word 文档中的表格,极大简化了从 Web 内容到 Word 文档的转换流程。这对于需要将网页上的表格数据导出为 Word 文档的场景尤为实用。
function App() {
const CreateTableFromHTML = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将字体和文档文件载入 VFS
await window.spire.FetchFileToVFS('msyh.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// HTML 字符串
let HTML = "<table border='2px'>" +
"<tr>" +
"<td>第1行,第1列</td>" +
"<td>第1行,第2列</td>" +
"</tr>" +
"<tr>" +
"<td>第2行,第1列</td>" +
"<td>第2行,第2列</td>" +
"</tr>" +
"</table>";
// 创建 Word 文档
let doc = new docModule.Document();
// 添加节
let section = doc.AddSection();
// 添加段落并追加 HTML 字符串
section.AddParagraph().AppendHTML(HTML);
// 定义输出文件名
const outputFileName = "CreateTableFromHTML_output.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>点击以下按钮,使用 HTML 在 Word 文档中创建表格。</h1>
<button onClick={CreateTableFromHTML}>
Generate
</button>
</div>
);
}
export default App;
通过 AppendHTML 转换后生成的 Word 表格完美保留了 HTML 中定义的边框样式和单元格结构:

嵌套表格是指在一个表格的单元格中再插入一个子表格,常用于实现复杂的文档布局,例如在产品目录中,主表格展示产品名称和描述,描述单元格内再嵌入一个包含规格参数(编号、项目、价格)的子表格。Spire.Doc 通过 Cell.AddTable 方法轻松实现嵌套表格的创建。
function App() {
const CreateNestedTable = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将字体和文档文件载入 VFS
await window.spire.FetchFileToVFS('msyh.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 创建新文档
let doc = new docModule.Document();
let section = doc.AddSection();
// 添加主表格(2行2列)
let table = section.AddTable({ showBorder: true });
table.ResetCells(1, 2);
// 设置列宽
table.Rows.get_Item(0).Cells.get_Item(0).SetCellWidth(70, docModule.CellWidthType.Point);
table.Rows.get_Item(0).Cells.get_Item(1).SetCellWidth(150, docModule.CellWidthType.Point);
table.Rows.get_Item(0).Height=150;
table.AutoFit(docModule.AutoFitBehaviorType.AutoFitToWindow);
// 向单元格插入内容
table.Rows.get_Item(0).Cells.get_Item(0).AddParagraph().AppendText("Spire.Doc for JavaScript");
let text = "Spire.Doc for JavaScript 是一个专业的 Word " +
"JavaScript 库,专为开发人员设计,可在任何 JavaScript " +
"平台上快速、高质量地创建、读取、写入、转换和打印 Word 文档文件。";
table.Rows.get_Item(0).Cells.get_Item(1).AddParagraph().AppendText(text);
table.Rows.get_Item(0).Cells.get_Item(1).AddParagraph();
// 在(第一行第二列)单元格中添加嵌套表格
let nestedTable = table.Rows.get_Item(0).Cells.get_Item(1).AddTable({ showBorder: true });
nestedTable.ResetCells(5, 2);
nestedTable.AutoFit(docModule.AutoFitBehaviorType.AutoFitToContents);
// 填充嵌套表格内容
nestedTable.Rows.get_Item(0).Cells.get_Item(0).AddParagraph().AppendText("功能模块");
nestedTable.Rows.get_Item(0).Cells.get_Item(1).AddParagraph().AppendText("典型应用场景");
nestedTable.Rows.get_Item(1).Cells.get_Item(0).AddParagraph().AppendText("文档生成");
nestedTable.Rows.get_Item(2).Cells.get_Item(0).AddParagraph().AppendText("格式转换");
nestedTable.Rows.get_Item(3).Cells.get_Item(0).AddParagraph().AppendText("内容编辑");
nestedTable.Rows.get_Item(4).Cells.get_Item(0).AddParagraph().AppendText("打印服务");
nestedTable.Rows.get_Item(1).Cells.get_Item(1).AddParagraph().AppendText("动态生成合同、发票、数据报告及邮件合并");
nestedTable.Rows.get_Item(2).Cells.get_Item(1).AddParagraph().AppendText("Word 与 PDF、HTML、RTF、XML、图片等格式互转");
nestedTable.Rows.get_Item(3).Cells.get_Item(1).AddParagraph().AppendText("提取文本/图片、添加水印、修订追踪与表单填写");
nestedTable.Rows.get_Item(4).Cells.get_Item(1).AddParagraph().AppendText("后台静默打印、自定义纸张与页面设置");
// 定义输出文件名
const outputFileName = "CreateNestedTable_output.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={CreateNestedTable}>
Generate
</button>
</div>
);
}
export default App;
嵌套表格生成的效果:主表格左侧显示产品名称,右侧的描述单元格内嵌了一个包含编号、项目和价格的规格明细表:

原因:创建 Blob 时 MIME 类型设置错误,浏览器无法正确识别文件格式。
解决:确保使用准确的 Word 文档 MIME 类型:
const modifiedFile = new Blob([fileArray], {
type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
});
原因:通过 AddTable({ showBorder: true }) 添加表格时边框默认启用,但通过 Table 构造函数直接创建的表格需要手动设置边框样式。
解决:使用构造函数创建表格时,显式设置边框类型:
let table = new docModule.Table(doc, false);
table.Format.Borders.BorderType = docModule.BorderStyle.Single;
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
在文档管理系统中,拆分 Word 文档是一个常见需求——将合并后的多章节文档按分节符拆分为独立文件,或将长文档按分页符分割为多个短文档。Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端直接完成文档拆分,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。
本文介绍两个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。以下示例默认已安装 Spire.Doc 并完成 WebAssembly 模块初始化。
Word 文档中的分节符(Section Break)用于分隔不同章节或版面布局,每个节可以拥有独立的页眉页脚、页码格式和页面设置。按分节符拆分是最常用、最稳定的拆分方式,适用于将合并后的多章节文档还原为独立文件。
核心流程分为三个阶段:首先将字体文件和目标 Word 文件载入 WASM 虚拟文件系统;然后实例化 Document 加载文件,遍历所有节,通过 Section.Clone() 将每个节克隆到新的 Document 对象中;最后将拆分后的文件打包为 ZIP 触发浏览器下载。
function App() {
const splitBySectionBreak = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
const inputFileName = 'Template_Docx_4.docx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// 创建输出目录
let outputDir = 'output/';
window.dotnetRuntime.Module.FS.mkdirTree(outputDir);
// 加载文档
const doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// 遍历每个节,克隆为独立文档
for (let i = 0; i < doc.Sections.Count; i++) {
const newWord = new docModule.Document();
newWord.Sections.Add(doc.Sections.get_Item(i).Clone());
newWord.SaveToFile({
fileName: outputDir + `Section-${i}.docx`,
fileFormat: docModule.FileFormat.Docx2013
});
newWord.Dispose();
}
doc.Dispose();
// 从 VFS 读取输出文件,打包为 ZIP 下载
const JSZip = require('jszip');
const zip = new JSZip();
let items = window.dotnetRuntime.Module.FS.readdir(outputDir);
items = items.filter(item => item !== '.' && item !== '..');
for (const item of items) {
const fileData = window.dotnetRuntime.Module.FS.readFile(outputDir + item);
zip.file(item, fileData);
}
const zipBlob = await zip.generateAsync({ type: 'blob' });
const url = URL.createObjectURL(zipBlob);
const a = document.createElement('a');
a.href = url;
a.download = 'SplitBySectionBreak.zip';
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Split Word Document By Section Break</h1>
<button onClick={splitBySectionBreak}>Generate</button>
</div>
);
}
export default App;
按分节符拆分后生成的独立 Word 文档

分页符(Page Break)是文档中手动插入或自动生成的分页标记。按分页符拆分适用于将长篇文档按页分割,每页内容保存为一个独立文档,常用于报告分页、合同条款拆分等场景。
与按分节符拆分不同,分页符位于段落内部的子对象层级,需要逐层遍历文档的节(Section)、段落(Paragraph)以及段落子对象,检测 Break 类型为 PageBreak 的元素。拆分时还需通过 CloneDefaultStyleTo、CloneThemesTo、CloneCompatibilityTo 等方法克隆原文档的样式和主题,确保拆分后的文档格式完整。
function App() {
const splitByPageBreak = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
const inputFileName = 'SplitWordFileByPageBreak.docx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// 创建输出目录
let outputDir = 'output/';
window.dotnetRuntime.Module.FS.mkdirTree(outputDir);
// 加载文档
const original = new docModule.Document();
original.LoadFromFile(inputFileName);
// 创建新文档,克隆样式和主题
let newWord = new docModule.Document();
let section = newWord.AddSection();
original.CloneDefaultStyleTo(newWord);
original.CloneThemesTo(newWord);
original.CloneCompatibilityTo(newWord);
let index = 0;
// 遍历所有节
for (let i = 0; i < original.Sections.Count; i++) {
let sec = original.Sections.get_Item(i);
// 遍历节中的所有子对象(段落、表格等)
for (let j = 0; j < sec.Body.ChildObjects.Count; j++) {
let obj = sec.Body.ChildObjects.get_Item(j);
if (obj instanceof docModule.Paragraph) {
let para = obj;
sec.CloneSectionPropertiesTo(section);
section.Body.ChildObjects.Add(para.Clone());
// 检测段落中的分页符
for (let k = 0; k < para.ChildObjects.Count; k++) {
let parobj = para.ChildObjects.get_Item(k);
if (parobj instanceof docModule.Break &&
parobj.BreakType === docModule.BreakType.PageBreak) {
let breakIndex = para.ChildObjects.IndexOf(parobj);
// 从段落中移除分页符
section.Body.LastParagraph.ChildObjects.RemoveAt(breakIndex);
// 保存当前文档
newWord.SaveToFile({
fileName: outputDir + `Page-${index}.docx`,
fileFormat: docModule.FileFormat.Docx2013
});
index++;
// 创建新文档继续
newWord = new docModule.Document();
section = newWord.AddSection();
original.CloneDefaultStyleTo(newWord);
original.CloneThemesTo(newWord);
original.CloneCompatibilityTo(newWord);
sec.CloneSectionPropertiesTo(section);
// 处理分页符后的剩余内容
section.Body.ChildObjects.Add(para.Clone());
if (section.Paragraphs.get_Item(0).ChildObjects.Count === 0) {
section.Body.ChildObjects.RemoveAt(0);
} else {
while (breakIndex >= 0) {
section.Paragraphs.get_Item(0).ChildObjects.RemoveAt(breakIndex);
breakIndex--;
}
}
}
}
}
if (obj instanceof docModule.Table) {
section.Body.ChildObjects.Add(obj.Clone());
}
}
}
// 保存最后一份文档
newWord.SaveToFile({
fileName: outputDir + `Page-${index}.docx`,
fileFormat: docModule.FileFormat.Docx2013
});
original.Dispose();
newWord.Dispose();
// 打包为 ZIP 下载
const JSZip = require('jszip');
const zip = new JSZip();
let items = window.dotnetRuntime.Module.FS.readdir(outputDir);
items = items.filter(item => item !== '.' && item !== '..');
for (const item of items) {
const fileData = window.dotnetRuntime.Module.FS.readFile(outputDir + item);
zip.file(item, fileData);
}
const zipBlob = await zip.generateAsync({ type: 'blob' });
const url = URL.createObjectURL(zipBlob);
const a = document.createElement('a');
a.href = url;
a.download = 'SplitByPageBreak.zip';
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Split Word Document By Page Break</h1>
<button onClick={splitByPageBreak}>Generate</button>
</div>
);
}
export default App;
按分页符拆分后生成的 Word 文档

原因:按分页符拆分时,仅克隆了段落内容,未同步克隆原文档的样式、主题和节属性,导致拆分后的文档丢失字体、颜色、页面设置等格式信息。
解决:创建新文档后,使用以下方法克隆原文档的样式和主题:
original.CloneDefaultStyleTo(newWord);
original.CloneThemesTo(newWord);
original.CloneCompatibilityTo(newWord);
sec.CloneSectionPropertiesTo(section);
原因:分页符位于段落子对象中,通过 BreakType 枚举判断。若遍历层级不正确,或未使用 instanceof 判断对象类型,会导致无法正确识别分页符。
解决:确保按 Paragraph.ChildObjects → instanceof Break → BreakType == BreakType.PageBreak 的顺序检测:
for (let k = 0; k < para.ChildObjects.Count; k++) {
let parobj = para.ChildObjects.get_Item(k);
if (parobj instanceof docModule.Break &&
parobj.BreakType === docModule.BreakType.PageBreak) {
// 找到分页符
}
}
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
批注是 Word 文档协作中不可或缺的功能,广泛用于审阅、校对和团队讨论场景。Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端直接完成批注的读写操作,通过虚拟文件系统(VFS)管理文档文件,无需后端服务支持,也无需安装 Microsoft Word。
本文介绍三个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。以下示例默认已安装 Spire.Doc 并完成 WebAssembly 模块初始化。
在实际文档审阅场景中,我们经常需要针对文档中的某段特定文字添加批注。实现思路是:首先通过 FindString 方法搜索定位目标文本,然后在该文本的前后分别插入 CommentMarkStart 和 CommentMarkEnd 标记,最后将 Comment 对象添加到段落中,从而将批注与指定文本关联起来。
import React from 'react';
function App() {
const AddCommentForSpecificText = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将目标 Word 文档载入 VFS
const inputFileName = "CommentTemplate.docx";
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);
// 创建 Document 实例并加载文档
let doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// 调用自定义函数,为指定文本添加批注
InsertComments(doc, "办公室", docModule);
// 保存文档
const outputFileName = "AddCommentForSpecificText.docx";
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([modifiedFileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
// 释放资源
doc.Dispose();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
// 自定义函数:为指定关键词添加批注
function InsertComments(doc, keystring, wasmModule) {
// 在文档中查找目标字符串
let find = doc.FindString(keystring, false, true);
// 创建批注起始标记和结束标记
let commentMarkStart = new wasmModule.CommentMark(doc, 1, wasmModule.CommentMarkType.CommentStart);
let commentMarkEnd = new wasmModule.CommentMark(doc, 1, wasmModule.CommentMarkType.CommentEnd);
// 创建批注对象,设置内容和作者
let comment = new wasmModule.Comment(doc);
comment.Body.AddParagraph().Text = "测试评论";
comment.Format.Author = "Administrator";
// 获取查找到的文本范围及其所在段落
let range = find.GetAsOneRange();
let para = range.OwnerParagraph;
// 获取文本范围在段落中的索引位置
let index = para.ChildObjects.IndexOf(range);
// 将批注添加到段落
para.ChildObjects.Add(comment);
// 在目标文本前后插入批注起始和结束标记
para.ChildObjects.Insert(index, commentMarkStart);
para.ChildObjects.Insert(index + 2, commentMarkEnd);
}
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>为特定文本添加评论。</h1>
<button onClick={AddCommentForSpecificText}>
Generate
</button>
</div>
);
};
export default App;
通过上述代码,可以在文档中搜索到指定关键词后,在其位置插入批注标记,从而实现将批注精准地添加到特定文本上。

当文档经过多人审阅后,往往包含大量批注。批量提取这些批注内容,便于汇总审阅意见或进行后续处理。Spire.Doc 提供了 Comments 集合,我们可以遍历该集合逐一读取每条批注的正文内容,然后导出为文本文件。
import React from 'react';
function App() {
const ExtractComment = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将目标 Word 文档载入 VFS
const inputFileName = "CommentSample.docx";
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);
// 创建 Document 实例并加载文档
let doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// 遍历所有批注,提取文本内容
let SB = [];
for (let i = 0; i < doc.Comments.Count; i++) {
let comment = doc.Comments.get_Item(i);
for (let j = 0; j < comment.Body.Paragraphs.Count; j++) {
let p = comment.Body.Paragraphs.get_Item(j);
SB.push(p.Text + "\n");
}
}
// 将提取的批注内容保存为文本文件
const outputFileName = 'ExtractComment.txt';
const blob = new Blob([SB.toString()], { type: "text/plain;charset=utf-8" });
// 释放资源
doc.Dispose();
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>从文档中提取评论。</h1>
<button onClick={ExtractComment}>
Generate
</button>
</div>
);
};
export default App;
通过 doc.Comments 集合可以访问文档中的所有批注,每条批注的正文内容通过 comment.Body.Paragraphs 获取。提取后的内容可以保存为纯文本文件,方便汇总查阅或导入其他系统。

在团队协作场景中,对已有批注进行回复和内容修正是常见的需求。Spire.Doc 支持通过 ReplyToComment 方法为批注添加回复,同时也支持修改批注内容或删除不需要的批注。以下示例演示了如何获取文档中的第一个批注,为其添加一条带图片的回复内容。
import React from 'react';
function App() {
const ReplyToComment = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将目标文档和图片载入 VFS
const inputFileName = "Comment.docx";
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);
const imageFile = "logo.png";
await window.spire.FetchFileToVFS(imageFile, '', `${process.env.PUBLIC_URL}/data/`);
// 创建 Document 实例并加载文档
let doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// 获取文档中的第一个批注
let comment1 = doc.Comments.get_Item(0);
// 创建回复批注,设置作者和内容
let replyComment1 = new docModule.Comment(doc);
replyComment1.Format.Author = "E-iceblue";
replyComment1.Body.AddParagraph().AppendText("Spire.Doc is a professional Word library for operating Word documents.");
// 将回复批注添加到原始批注
comment1.ReplyToComment(replyComment1);
// 加载图片并插入到回复批注中
let docPicture = new docModule.DocPicture(doc);
docPicture.LoadImage(imageFile);
replyComment1.Body.Paragraphs.get_Item(0).ChildObjects.Add(docPicture);
// 保存文档
const outputFileName = "ReplyToComment.docx";
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx });
const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([modifiedFileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
// 释放资源
doc.Dispose();
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>添加回复评论。</h1>
<button onClick={ReplyToComment}>
Generate
</button>
</div>
);
};
export default App;
除了回复批注外,还可以通过 Comments.RemoveAt(index) 方法删除指定批注,或通过 Body.Paragraphs.get_Item(0).Replace(...) 修改批注中的文本内容:
// 修改第一个批注的内容
doc.Comments.get_Item(0).Body.Paragraphs.get_Item(0)
.Replace({ given: "原文本", replace: "修改后的文本", caseSensitive: false, wholeWord: false });
// 删除第二个批注
doc.Comments.RemoveAt(1);

原因:批注标记 CommentMarkStart 和 CommentMarkEnd 的插入位置不正确,或 Comment 对象未正确添加到段落中。批注的起始标记必须位于被批注文本之前,结束标记位于被批注文本之后,且 Comment 对象本身也需要添加到同一段落中。
解决:确保按正确顺序操作——先获取目标文本的索引位置,然后依次插入 CommentMarkStart、将 Comment 添加到段落末尾,最后在文本后插入 CommentMarkEnd。
原因:文档中可能不存在批注,或者批注内容存储在嵌套结构中。另外,如果文档加载时路径错误或文件未成功载入 VFS,也会导致无法读取批注。
解决:提取前先检查 doc.Comments.Count 是否大于 0,确认文档中包含批注。同时确保通过 FetchFileToVFS 正确加载了文档文件:
await window.spire.FetchFileToVFS(
'CommentSample.docx', '', `${process.env.PUBLIC_URL}/static/data/`
);
原因:ReplyToComment 方法的调用对象是原始批注,如果误将回复批注作为调用对象,或者调用了多次导致引用混乱,可能导致批注结构异常。
解决:确保始终以文档中已有的原始批注对象调用 ReplyToComment 方法,新创建的 Comment 对象作为参数传入:
// 正确:原始批注调用 ReplyToComment,新批注作为参数
existingComment.ReplyToComment(replyComment);
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
Word 文档变量(DocVariable)是一种轻量级的字段机制,允许在文档中定义占位符,并通过代码动态填充或更新内容。这种机制在模板化文档生成、批量信函制作和自动化报表输出等场景中非常实用。Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端直接完成变量的全部操作,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。
本文介绍三个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。以下示例默认已安装 Spire.Doc 并完成 WebAssembly 模块初始化。
添加文档变量的核心流程分为三个阶段:首先通过 FetchFileToVFS 将字体文件载入 WASM 虚拟文件系统;然后实例化 Document,在段落中插入 DocVariable 域字段,并通过 Variables.Add 方法为变量赋值;最后保存文档并从 VFS 读取生成的文件,封装为 Blob 后触发浏览器下载。
import React from 'react';
function App() {
const addVariables = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 创建文档对象
const doc = new docModule.Document();
// 添加一个节
const section = doc.AddSection();
// 添加一个段落
const paragraph = section.AddParagraph();
// 在段落中插入一个 DocVariable 域字段
paragraph.AppendField("A1", docModule.FieldType.FieldDocVariable);
// 为 DocVariable 域字段对应的变量赋值
doc.Variables.Add("A1", "12");
// 更新域以显示变量值
doc.IsUpdateFields = true;
// 定义输出文件名
const outputFileName = "AddVariables_out.docx";
// 保存文档
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
// 释放资源
doc.Dispose();
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>添加文档变量。</h1>
<button onClick={addVariables}>
Generate
</button>
</div>
);
};
export default App;
通过 Variables.Add 方法添加变量后,文档中的 DocVariable 域字段会被替换为对应的变量值。

对于已包含变量的 Word 模板文档,可以通过索引或变量名称检索变量信息。Spire.Doc 提供了多种检索方式:通过索引获取变量名称和值,或直接通过变量名获取对应的值。
import React from 'react';
function App() {
const retrieveVariables = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
const inputFileName = 'Template_Docx_6.docx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);
// 加载文档
const doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// 通过索引获取变量名称和值
const nameByIndex = doc.Variables.GetNameByIndex(0);
const valueByIndex = doc.Variables.GetValueByIndex(0);
// 通过变量名直接获取值
const valueByName = doc.Variables.get_Item("A1");
// 遍历所有变量
let stringBuilder = [];
stringBuilder.push("This document has following variables:\n");
for (let i = 0; i < doc.Variables.Count; i++) {
let name = doc.Variables.GetNameByIndex(i);
let value = doc.Variables.GetValueByIndex(i);
stringBuilder.push("Name: " + name + ", " + "Value: " + value + "\n");
}
// 将结果写入文本文件
const outputFileName = "RetrieveVariables_out.txt";
window.dotnetRuntime.Module.FS.writeFile(outputFileName, stringBuilder.join(""));
// 从 VFS 读取生成的文件,触发下载
const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([modifiedFileArray], { type: 'text/plain' });
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>获取文档变量。</h1>
<button onClick={retrieveVariables}>
Generate
</button>
</div>
);
}
export default App;
检索结果以文本文件输出,清晰列出文档中所有变量的名称及对应的值。

当模板文档中存在不再需要的变量时,可以通过 Variables.Remove 方法按变量名称将其移除。移除后配合 IsUpdateFields 属性更新域,确保生成的文档干净无冗余。
function App() {
const removeVariables = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查模块是否就绪
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
const inputFileName = 'Template_Docx_6.docx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);
// 加载文档
const doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// 按变量名称移除变量
doc.Variables.Remove("A1");
let name = doc.Variables.GetNameByIndex(0);
doc.Variables.Remove(name);
doc.Variables.Remove(doc.Variables.GetNameByIndex(0));
doc.IsUpdateFields = true;
// 定义输出文件名
const outputFileName = "RemoveVariables_out.docx";
// 保存文档
doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.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);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>删除文档变量。</h1>
<button onClick={removeVariables}>
Generate
</button>
</div>
);
}
export default App;
移除变量后生成的文档中,目标变量及其对应的 DocVariable 域字段将被清除,文档内容更加简洁。

原因:DocVariable 域字段创建后,默认不会自动更新显示变量值。如果未设置 IsUpdateFields 属性,文档中会保留域代码文本。
解决:保存文档前将 IsUpdateFields 属性设置为 true:
document.IsUpdateFields = true;
原因:传入的变量名称大小写或拼写与文档中实际定义的变量名不一致,导致匹配失败。
解决:先通过遍历 document.Variables 集合,使用 GetNameByIndex 方法确认文档中实际的变量名称,再按准确名称获取值:
for (let i = 0; i < document.Variables.Count; i++) {
let name = document.Variables.GetNameByIndex(i);
let value = document.Variables.GetValueByIndex(i);
console.log("Name: " + name + ", Value: " + value);
}
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。