PDF 在流转途中常带着上一轮审阅留下的批注:有人标了重点,有人写了修改意见,有人贴了「待确认」。这些留痕如果原样转给下一方,既容易造成误读,也可能把内部讨论一并带出去。要在阅读器里逐条手动删掉,文档一多就顾不过来。
本文介绍用 Spire.PDF for JavaScript 删除 PDF 文档中的注释。它基于 WebAssembly 在浏览器端直接加载、修改与保存 PDF 文档,全过程在本地完成,通过虚拟文件系统(VFS)读写文件,无需后端配合。删除围绕 PdfPage.Annotations 集合进行:既可以按索引移除某一条,也可以整页一次性清空。
本文介绍两个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.PDF for JavaScript。以下示例默认已安装 Spire.PDF 并完成 WebAssembly 模块初始化。
删除指定的注释
Spire.PDF for JavaScript 提供 PdfPage.Annotations 集合,用于管理页面上的注释。RemoveAt() 按索引移除其中一条,索引从 0 开始。集合是有序的,删除后后续注释的下标会整体前移。
function App() {
const deleteSpecificAnnotation = 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 对象并加载文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// 删除第 1 页上索引为 0 的那条注释
doc.Pages.get_Item(0).Annotations.RemoveAt(0);
const outputFileName = '删除指定注释.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// 从 VFS 读取生成的文件,触发下载
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>删除指定的注释</h1>
<button onClick={deleteSpecificAnnotation} id="btn-1">
开始删除
</button>
</div>
);
}
export default App;
第 1 页上索引为 0 的注释已被移除,其余注释保持不变:

删除文档中全部注释
Spire.PDF for JavaScript 还提供 PdfAnnotationCollection.Clear() 方法,用于清空某个页面上的全部注释。它不区分注释类型与数量,整页一并移除。要清掉整份文档,遍历 doc.Pages 对每一页各调用一次即可。
function App() {
const deleteAllAnnotations = 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 对象并加载文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// 遍历每一页,清空该页的全部注释
for (let i = 0; i < doc.Pages.Count; i++) {
doc.Pages.get_Item(i).Annotations.Clear();
}
const outputFileName = '删除全部注释.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// 从 VFS 读取生成的文件,触发下载
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>删除文档中全部注释</h1>
<button onClick={deleteAllAnnotations} id="btn-2">
开始清除
</button>
</div>
);
}
export default App;
文档各页的注释已被清空,页面正文内容原样保留:

常见问题
删掉的不是想要的那一条
原因:RemoveAt(index) 按索引定位,而文本注释或自由文本注释在生成时往往会自动派生一条弹出式(popup)子注释,两者都计入 Annotations 集合,导致实际下标与页面上看到的注释条数对不上。
解决:先遍历集合,确认每一条的索引与类型,再决定删哪一个;只想删文本注释本体时,跳过弹出式子注释:
const annotations = doc.Pages.get_Item(0).Annotations;
for (let i = 0; i < annotations.Count; i++) {
// 弹出式注释是文本注释派生的子注释,跳过
if (annotations.get_Item(i) instanceof pdfModule.PdfPopupAnnotationWidget) continue;
annotations.RemoveAt(i);
break;
}
正序循环删除时漏删了一半
原因:RemoveAt() 删掉一条后,后面所有注释的下标会整体减一。用 for (let i = 0; i < annotations.Count; i++) 正序逐个删,每删一条就跳过了紧随其后的那一条。
解决:倒序遍历删除,或直接对该页调用 Clear():
// 倒序删除,避免下标前移导致漏删
const annotations = doc.Pages.get_Item(0).Annotations;
for (let i = annotations.Count - 1; i >= 0; i--) {
annotations.RemoveAt(i);
}
Clear() 会不会连正文一起清掉
原因:Clear() 的作用范围是当前页的 Annotations 集合,这个集合里只存放注释对象,不含正文、图片或表单域。
解决:Clear() 只清注释,页面正文原样保留;只想清掉部分页面时按页调用即可,不必遍历整份文档:
// 只清第 2 页(索引 1)的注释
doc.Pages.get_Item(1).Annotations.Clear();
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。









