书签是 Word 文档中一种不可见的定位标记,它充当文档中的"坐标",能够精确标记某个位置或一段文本范围。但书签的真正价值不仅在于定位——通过编程手段获取书签范围内的内容、替换其中的占位文本、删除不再需要的内容,或在书签位置插入文本、段落、表格和图片,开发者可以实现合同模板的自动填充、报告数据的动态注入、表单内容的批量清理等高级文档处理流程。可以说,围绕着书签内容"读、写、删、插"的操作组合,构成了 Word 自动化的核心工作流。
Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端直接完成书签内容的读取、替换、删除以及元素插入操作,通过虚拟文件系统(VFS)管理文件,无需后端服务支持。
本文介绍四个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。以下示例默认已安装 Spire.Doc 并完成 WebAssembly 模块初始化。
获取书签内容
获取书签内容是对书签进行任何操作的前提。通过 BookmarksNavigator 定位到指定书签后,GetBookmarkContent 方法将书签范围内的内容作为 TextBodyPart 对象返回,开发者可以遍历其 BodyItems 集合下的元素进行获取。
function App() {
const bookmarkContent = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查 WASM 模块是否已加载完成
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将 Word 文档载入虚拟文件系统(VFS)
const inputFileName = '合同模板.docx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);
// 加载 Word 文档
const doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// 创建 BookmarksNavigator 并定位到书签
let navigator = new docModule.BookmarksNavigator(doc);
navigator.MoveToBookmark("合同书签");
let textBodyPart = navigator.GetBookmarkContent();
// 迭代书签内容中的元素,提取文本
let text = "";
for (let i = 0; i < textBodyPart.BodyItems.Count; i++) {
let item = textBodyPart.BodyItems.get_Item(i);
if (item instanceof docModule.Paragraph) {
for (let j = 0; j < item.ChildObjects.Count; j++) {
let childObject = item.ChildObjects.get_Item(j);
if (childObject instanceof docModule.TextRange) {
text += childObject.Text;
}
}
}
}
// 保存为 .txt 文件
const outputFileName = "获取的内容.txt";
// TXT 文件保存到 VFS 并触发下载
window.dotnetRuntime.Module.FS.writeFile(outputFileName, text);
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
// 释放资源
doc.Dispose();
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Get Bookmark Content from Word Document</h1>
<button onClick={bookmarkContent}>
Generate
</button>
</div>
);
}
export default App;
执行上述代码,将把书签"合同书签"范围内的文本内容提取并保存为独立的 .txt 文件:

替换书签内容
替换书签内容是在文档模板填充中最常用的操作。通过 BookmarksNavigator 定位到书签后,调用ReplaceBookmarkContent 方法不仅支持替换为纯文本,还支持替换为表格等复杂元素,适合在合同生成、报表填充等场景中替换占位符。
function App() {
const replaceBookmarkContent = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查 WASM 模块是否已加载完成
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将字体和 Word 文件载入 VFS
await window.spire.FetchFileToVFS('SIMSUN.TTC', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = '书签文档.docx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);
// 加载 Word 文档
const doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// 创建 BookmarksNavigator 并定位到书签
let navigator = new docModule.BookmarksNavigator(doc);
navigator.MoveToBookmark("书签1");
// 替换“书签1”的内容——用文本替换
navigator.ReplaceBookmarkContent({ text: "这是替换到书签的文本", saveFormatting: true });
// 继续替换"书签2"的内容——用表格替换
navigator.MoveToBookmark("书签2");
// 创建表格
let table = new docModule.Table(doc, true);
table.ResetCells(4, 5);
// 创建数据表并将数据填充到表格中
let dt = [
["城市", "省份", "人口", "面积(km²)", "简称"],
["北京", "北京", "2189万", "16410", "京"],
["上海", "上海", "2475万", "6340", "沪"],
["广州", "广东", "1867万", "7434", "穗"]];
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 5; j++) {
table.Rows.get_Item(i).Cells.get_Item(j).AddParagraph().AppendText(dt[i][j]);
}
}
// 创建 TextBodyPart 实例并将表格添加到其中
let part = new docModule.TextBodyPart({ doc: doc });
part.BodyItems.Add(table);
// 用 TextBodyPart 对象替换当前书签内容
navigator.ReplaceBookmarkContent({ bodyPart: part });
// 保存为新的 .docx 文件
const outputFileName = "替换书签.docx";
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
// 从 VFS 读取生成的文件并触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { 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);
// 释放资源
doc.Dispose();
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Replace Bookmark Content in Word</h1>
<button onClick={replaceBookmarkContent}>
Generate
</button>
</div>
);
}
export default App;
此方式可以替换书签内容为纯文本,也支持替换为表格等复杂元素。书签标记本身在替换后仍然保留,便于后续再次定位。执行效果如下图所示:

删除书签内容
删除书签内容与删除书签标记是两个不同的操作。通过 BookmarksNavigator 定位到书签后,调用 DeleteBookmarkContent 方法可以移除书签范围内的文本内容,但保留书签标记本身,以便后续重新填入内容。如果只需清空内容而保留定位标记,此方法是首选。
function App() {
const deleteBookmarkContent = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查 WASM 模块是否已加载完成
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将 Word 文件载入 VFS
const inputFileName = '合同模板.docx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);
// 加载 Word 文档
const doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// 创建 BookmarksNavigator 并定位到书签
let navigator = new docModule.BookmarksNavigator(doc);
navigator.MoveToBookmark("合同书签");
// 删除书签内容,保留书签标记
navigator.DeleteBookmarkContent(true);
// 保存为新的 .docx 文件
const outputFileName = "删除书签内容.docx";
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
// 从 VFS 读取生成的文件并触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { 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);
// 释放资源
doc.Dispose();
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Delete Bookmark Content in Word Document</h1>
<button onClick={deleteBookmarkContent}>
Generate
</button>
</div>
);
}
export default App;
使用
DeleteBookmarkContent删除的是书签范围内的文本内容,书签标记本身仍然保留;而Bookmarks.Remove移除的是书签标记,范围内的文本不受影响。
执行后文档中书签"合同书签"范围内的文本被移除,但书签标记仍保留在文档中:

在书签位置插入文本、段落、表格和图片
Spire.Doc 支持在书签位置灵活插入多种类型的文档元素。提供 InsertText、InsertParagraph、InsertTable 等方法插入文本、段落和表格。同时也可以根据书签起始节点在段落 ChildObjects 中的索引来插入多种元素。
function App() {
const insertElementsAtBookmark = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
// 检查 WASM 模块是否已加载完成
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 加载字体和 Word 文档到 VFS
await window.spire.FetchFileToVFS('MSYH.TTC', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = '书签文档.docx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);
// 创建 Document 对象并加载文档
const doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// 定位到书签位置
let navigator = new docModule.BookmarksNavigator(doc);
navigator.MoveToBookmark("书签1");
// 1. 插入文本
navigator.InsertText("这是插入的文本内容。", true);
// 2. 插入段落
let newParagraph = new docModule.Paragraph(doc);
newParagraph.AppendText("这是插入的段落内容。")
navigator.MoveToBookmark("书签2");
navigator.InsertParagraph(newParagraph);
// 3. 插入表格 — 2 行 3 列
let table = new docModule.Table(doc, true);
table.ResetCells(2, 3);
table.Rows.get_Item(0).Cells.get_Item(0).AddParagraph().AppendText("名称");
table.Rows.get_Item(0).Cells.get_Item(1).AddParagraph().AppendText("数量");
table.Rows.get_Item(0).Cells.get_Item(2).AddParagraph().AppendText("备注");
table.Rows.get_Item(1).Cells.get_Item(0).AddParagraph().AppendText("产品 A");
table.Rows.get_Item(1).Cells.get_Item(1).AddParagraph().AppendText("100");
table.Rows.get_Item(1).Cells.get_Item(2).AddParagraph().AppendText("已入库");
navigator.MoveToBookmark("书签3");
navigator.InsertTable(table);
// 4. 插入图片
const imageFileName = '图片.png';
await window.spire.FetchFileToVFS(imageFileName, '', `${process.env.PUBLIC_URL}/data/`);
let picture = new docModule.DocPicture(doc);
picture.LoadImage(imageFileName);
picture.Width = 100;
picture.Height = 200;
navigator.MoveToBookmark("书签4");
// 获取书签起始节点
let start = navigator.CurrentBookmark.BookmarkStart;
// 获取书签所在的段落
let bookmarkPara = start.OwnerParagraph;
// 获取书签起始节点在段落中的索引位置
let startIndex = bookmarkPara.ChildObjects.IndexOf(start);
// 在书签起始节点后插入图片
bookmarkPara.ChildObjects.Insert(startIndex + 1, picture);
// 保存文档为 .docx 格式
const outputFileName = "插入元素到书签.docx";
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
// 从 VFS 读取生成的文件并触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { 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);
// 释放 Document 资源
doc.Dispose();
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Insert Elements at Bookmark Position</h1>
<button onClick={insertElementsAtBookmark}>
Generate
</button>
</div>
);
}
export default App;
执行上述代码,将在书签处插入文本、新段落、表格和图片,原有内容不会被覆盖:

常见问题
替换书签内容后,原来的字体、字号、颜色等格式丢了怎么办?
ReplaceBookmarkContent 默认会用纯文本替换,原格式会丢失。如果需要保留书签原有的格式,传入 saveFormatting: true:
navigator.ReplaceBookmarkContent({ text: "新内容", saveFormatting: true });
这样替换后的文本会沿用书签原来的字体、字号、颜色等格式。
如何批量处理文档中的多个书签?
遍历 doc.Bookmarks 集合,逐个定位并操作:
for (let i = 0; i < doc.Bookmarks.Count; i++) {
let bookmark = doc.Bookmarks.get_Item(i);
navigator.MoveToBookmark(bookmark.Name);
// 执行替换、删除或插入操作
}
DeleteBookmarkContent 和直接删除书签标记有什么区别?
DeleteBookmarkContent:只清空书签范围内的内容,书签标记保留在文档中,后续仍可通过书签名称定位并填入新内容。Bookmarks.Remove:移除书签标记本身,书签范围内的内容不受影响,但书签名称会消失,无法再定位。
两者互补,根据需求选择:需要保留"占位"能力就用 DeleteBookmarkContent,不需要书签了就移除标记。
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。







