PDF 里的超链接本该是最省事的一环:点一下就到,不用复制、不用手打。可要加的时候,麻烦事不少。新建一份文档时希望它一开始就带上下载页、联系邮箱和产品页。拿到一份已经排好的旧文档,又希望正文里反复出现的产品名都指向同一页介绍。手工做法是一处一处框选、粘贴地址,文档一大就做不完。
把这件事挪到浏览器里做,用的是 Spire.PDF for JavaScript:它基于 WebAssembly 直接加载、修改与保存 PDF 文档,PdfTextWebLink 一步画出可见的链接文字,PdfFileLinkAnnotation 挂上文档链接。全过程在本地完成,通过虚拟文件系统(VFS)读写文件,无需后端配合。
本文介绍两个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.PDF for JavaScript。以下示例默认已安装 Spire.PDF 并完成 WebAssembly 模块初始化。
在 PDF 文档中添加超链接
从零新建文档时,页面上的一切都由代码决定,链接也分了几类:
- 简单文字链接:把网址当普通文字画出来,代码不给它挂任何注解;能不能点由阅读器决定,Chrome 等会自动把网址识别成可点链接,所以它照样能点,这里只作与显式挂注解链接的对照。
- 超文本链接:
PdfTextWebLink配好Text、Url、Font、Brush,DrawTextWebLink()一步画出带下划线的链接文字。 - 文档链接:
PdfFileLinkAnnotation(热区矩形, 目标文件),热区要自己定义。
function App() {
const addLinksToNewPdf = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 画中文要用字体,先载入 VFS
const fontVfs = '/Library/Fonts/ARIAL UNICODE MS.TTF';
await window.spire.FetchFileToVFS('ARIAL UNICODE MS.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 创建空白文档
const doc = new pdfModule.PdfDocument();
// 新建一个节,整节页边距设为 0:坐标即页面坐标
const section = doc.Sections.Add();
section.PageSettings.Size = pdfModule.PdfPageSize.A4();
const margins = new pdfModule.PdfMargins();
margins.Top = 0;
margins.Bottom = 0;
margins.Left = 0;
margins.Right = 0;
section.PageSettings.Margins = margins;
const page = section.Pages.Add();
const font = new pdfModule.PdfTrueTypeFont({ fontFile: fontVfs, size: 13 });
const linkFont = new pdfModule.PdfTrueTypeFont({ fontFile: fontVfs, size: 13, style: pdfModule.PdfFontStyle.Underline });
const format = new pdfModule.PdfStringFormat({ alignment: pdfModule.PdfTextAlignment.Left });
// 画一行普通文字当标签
const drawLabel = (text, y) => {
page.Canvas.DrawString({
s: text, font: font, brush: pdfModule.PdfBrushes.get_Black(), x: 60, y: y, format: format,
});
};
// 画一行带下划线的文字,并把它的矩形交回去当热区
const drawLinkText = (text, y) => {
const size = linkFont.MeasureString({ text: text });
page.Canvas.DrawString({
s: text, font: linkFont, brush: pdfModule.PdfBrushes.get_Blue(), x: 160, y: y, format: format,
});
return new pdfModule.RectangleF({ x: 160, y: y, width: size.Width, height: size.Height });
};
const url = 'https://www.e-iceblue.cn/Introduce/Spire-PDF-Javascript.html';
// 1) 简单文字链接:只把网址当普通文字画出来,不挂注解(可点与否取决于阅读器)
let y = 80;
drawLabel('简单文字链接:', y);
drawLinkText(url, y);
// 2) 超文本链接:DrawTextWebLink 一步画出文字并挂上链接
y += 34;
drawLabel('超文本链接:', y);
const webLink = new pdfModule.PdfTextWebLink();
webLink.Text = '访问官网';
webLink.Url = url;
webLink.Font = linkFont;
webLink.Brush = pdfModule.PdfBrushes.get_Blue();
webLink.DrawTextWebLink({ graphics: page.Canvas, location: new pdfModule.PointF(160, y) });
// 3) 邮件链接:同一个类,Url 换成 mailto:
y += 34;
drawLabel('邮件链接:', y);
const mailLink = new pdfModule.PdfTextWebLink();
mailLink.Text = '联系技术支持';
mailLink.Url = 'mailto:该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。';mailLink.Font = linkFont;mailLink.Brush = pdfModule.PdfBrushes.get_Blue();mailLink.DrawTextWebLink({graphics:page.Canvas,location:new pdfModule.PointF(160,y)});// 4) 文档链接:热区矩形 + 目标文件 y += 34;drawLabel('文档链接:',y);const fileName = 'Report.xlsx';const fileBounds = drawLinkText('打开文件',y);page.Annotations.Add(new pdfModule.PdfFileLinkAnnotation(fileBounds,fileName));// 保存生成的文档 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 downloadUrl = URL.createObjectURL(blob);const a = document.createElement('a');a.href = downloadUrl;a.download = outputFileName;a.click();URL.revokeObjectURL(downloadUrl);};return ( <div style={{textAlign:'center',height:'300px'}}><h1>添加超链接</h1><button onClick={addLinksToNewPdf}>开始创建 </button></div>);}export default App;新建文档中简单文字、超文本、邮件与文档四种链接均已就位:

给检索到的文字添加超链接
已有文档要加链接,做法反过来:先在文档里找位置,再往上面盖链接。PdfTextFinder按关键字检索指定页面上的文字,每处命中都带一个包围矩形。拿它构造 PdfUriAnnotation并加入页面注解集合,链接就精确落在原文上,不用自己去量坐标。
function App(){const addHyperlinksToText = 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);// 取第一页 const page = doc.Pages.get_Item(0);// 在该页检索关键字;Parameter 默认区分大小写,这里改成忽略大小写 const finder = new pdfModule.PdfTextFinder(page);finder.Options.Parameter = pdfModule.TextFindParameter.IgnoreCase;const finds = finder.Find('Aurora');// 每一处命中都生成一个链接注解 const linkUrl = 'https://www.e-iceblue.cn/Introduce/Spire-PDF-Javascript.html';for (let i = 0;i <finds.length;i++){// 命中项的包围矩形就是链接热区 const annotation = new pdfModule.PdfUriAnnotation({rectangle:finds.get(i).Bounds[0]});annotation.Uri = linkUrl;// 把注解挂到页面注解集合上 page.Annotations.Add(annotation);}// 保存生成的文档 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 downloadUrl = URL.createObjectURL(blob);const a = document.createElement('a');a.href = downloadUrl;a.download = outputFileName;a.click();URL.revokeObjectURL(downloadUrl);};return ( <div style={{textAlign:'center',height:'300px'}}><h1>给检索到的文字添加超链接</h1><button onClick={addHyperlinksToText}>开始添加 </button></div>);}export default App;文档中三处 Aurora 均已挂上超链接:

常见问题
正文里明明有这个字,Find()却一处都没搜到
原因:Options.Parameter默认是 TextFindParameter.None(区分大小写),检索 aurora匹配不到 Aurora;而且 finder 只在构造时传入的那一页上检索。
解决:设成 IgnoreCase;要检索全文档就逐页各建一个 finder:
finder.Options.Parameter = pdfModule.TextFindParameter.IgnoreCase;实测:Aurora在第 1 页出现 3 处,区分大小写只能搜到 0 处。
链接加上了,打开文件却看不到任何提示
原因:这类链接注解只是点击热区,Spire 不为它生成外观流(/AP),实测 Chrome(PDFium)与 PyMuPDF(mupdf)都不给它画边框;设 Border/Color也只写进注解字典(/Border [0 0 1]、/C [0 0 1]),页面上照样看不出来。
解决:链接照样可点。功能点 1 的超文本、邮件、简单文字、文档链接,文字都是代码自己画上去的,本就可见;功能点 2 盖在原文上的热区想看得见,别靠注解边框——在链接位置用 page.Canvas.DrawString()画一条下划线。
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。









