PDF 文档中的书签(Bookmark)以树形结构组织文档大纲,是长篇文档快速导航的核心工具。当文档包含多级书签时,默认的展开或折叠状态会直接影响读者打开文档时看到的大纲全貌。借助 Spire.PDF for JavaScript,可以在 React 应用中重新设置书签的展开与折叠状态,让文档打开时按预期呈现所需的大纲层级。
Spire.PDF for JavaScript 基于 WebAssembly 在浏览器端直接处理 PDF 文档,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。控制书签展开或折叠的核心是书签对象的 ExpandBookmark 属性:设为 true 展开该节点及其子书签,设为 false 则折叠收起其子书签。对于多级书签,可以递归遍历 PdfBookmarkCollection 集合统一设置,也可以按索引精确定位某个节点单独控制。
本文介绍两个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.PDF for JavaScript。以下示例默认已安装 Spire.PDF 并完成 WebAssembly 模块初始化。
展开所有 PDF 书签
Spire.PDF for JavaScript 可以通过 PdfDocument.Bookmarks 获取文档的书签集合。由于书签支持多级嵌套,需要编写一个递归函数遍历 PdfBookmarkCollection:先递归处理子书签,再把当前节点的 ExpandBookmark 属性统一设为 true,从而让文档打开时所有层级的书签全部展开。
function App() {
const expandAllBookmarks = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将待处理的 PDF 文件载入 VFS
const inputFileName = '示例.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 PdfDocument 对象并加载 PDF 文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// 递归遍历书签集合,展开所有层级的书签
function expandBookmarks(collection, expand) {
// 集合为空时结束递归
if (collection.Count === 0) {
return;
}
for (let i = 0; i < collection.Count; i++) {
let bookmark = collection.get_Item(i);
// 先递归处理子书签
expandBookmarks(bookmark, expand);
// 再设置当前书签的展开状态
bookmark.ExpandBookmark = expand;
}
}
// 展开文档中的所有书签
expandBookmarks(doc.Bookmarks, true);
// 保存文档并触发下载
const outputFileName = "展开所有书签.pdf";
doc.SaveToFile(outputFileName);
doc.Close();
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: "application/pdf" });
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>展开所有 PDF 书签</h1>
<button onClick={expandAllBookmarks}>
开始展开
</button>
</div>
);
}
export default App;
递归展开所有层级书签后的文档

展开或折叠指定 PDF 书签
如果只需要控制某几个书签节点,可以通过 PdfBookmarkCollection.get_Item 按索引定位目标书签,再分别设置其 ExpandBookmark 属性。将某个节点的 ExpandBookmark 设为 true 会展开该节点下的子书签,设为 false 则会收起子书签,由此可以实现「部分展开、部分折叠」的精确控制。
function App() {
const toggleSpecificBookmarks = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将待处理的 PDF 文件载入 VFS
const inputFileName = '示例.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 PdfDocument 对象并加载 PDF 文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// 展开第一个书签(第一章),其下的子书签一并显示
doc.Bookmarks.get_Item(0).ExpandBookmark = true;
// 折叠第二个书签(第二章),其下的子书签将被收起
doc.Bookmarks.get_Item(1).ExpandBookmark = false;
// 展开第三个书签(第三章)
doc.Bookmarks.get_Item(2).ExpandBookmark = true;
// 保存文档并触发下载
const outputFileName = "展开折叠指定书签.pdf";
doc.SaveToFile(outputFileName);
doc.Close();
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: "application/pdf" });
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>展开或折叠指定 PDF 书签</h1>
<button onClick={toggleSpecificBookmarks}>
开始处理
</button>
</div>
);
}
export default App;
按索引展开或折叠指定书签后的文档

常见问题
为什么设置了 ExpandBookmark 后子书签仍然不显示
原因:ExpandBookmark 控制的是「该节点的子书签是否显示」。如果某个书签的上层节点处于折叠状态,那么无论其自身 ExpandBookmark 设为 true,只要父节点是折叠的,它依然不会被显示出来。
解决:从根节点开始逐层展开,或直接使用递归方式把整棵书签树的 ExpandBookmark 都设为 true:
function expandBookmarks(collection) {
for (let i = 0; i < collection.Count; i++) {
let bookmark = collection.get_Item(i);
bookmark.ExpandBookmark = true;
expandBookmarks(bookmark);
}
}
expandBookmarks(doc.Bookmarks);
如何只展开多级书签中的某一层
原因:书签是树形结构,PdfBookmarkCollection 的每个节点还可以继续通过 get_Item 访问其子集合,需要按层级逐级定位。
解决:先定位到目标层级的父节点,再设置该节点的 ExpandBookmark。例如只展开第二章下的第一个子书签:
// 取第二个书签(第二章)
let chapterTwo = doc.Bookmarks.get_Item(1);
// 取该章下的第一个子书签
let sectionOne = chapterTwo.get_Item(0);
// 展开该子书签
sectionOne.ExpandBookmark = true;
ExpandBookmark 的展开或折叠状态保存在哪里
原因:书签的展开与折叠状态会随书签本身写入 PDF 的大纲(Outlines)结构中,属于文档内容的一部分,而不是阅读器的临时设置。
解决:设置并保存后,用任何支持 PDF 标准大纲的阅读器(如 Adobe Acrobat、Edge、Chrome 内置阅读器的书签面板)打开,都会按保存时的状态呈现。若需还原为全部折叠,只需把对应节点的 ExpandBookmark 设为 false 后重新保存:
// 折叠第一个书签
doc.Bookmarks.get_Item(0).ExpandBookmark = false;
doc.SaveToFile(outputFileName);
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。









