如何让PDF.js加载的PDF中链接可点击?(单HTML文件场景)
解决PDF.js单HTML展示PDF时内部链接无法点击的问题
问题背景
基于PDF.js官方示例修改了单HTML文件实现PDF展示,但PDF内部的链接无法点击,且无法下载仓库源码进行开发。仅需实现PDF展示功能,需解决链接点击问题。
解决方案
canvas渲染PDF仅生成静态图像,不会自动保留交互功能。需手动提取PDF页面中的链接注释,在canvas上方构建可点击的交互层:
- 给每个canvas添加相对定位的容器,用于承载可点击链接元素
- 页面渲染完成后,获取当前页面的所有注释,筛选出链接类型的注释
- 将PDF注释的原始坐标通过viewport转换为canvas上的实际显示位置
- 在容器内创建透明的可点击div,绑定点击事件跳转至目标链接
修改后的完整代码
<script src="//mozilla.github.io/pdf.js/build/pdf.mjs" type="module"></script> <script type="module"> var url = 'https://lukasjarmara.github.io/hosting/What%20Next%20Catalog.pdf'; var { pdfjsLib } = globalThis; pdfjsLib.GlobalWorkerOptions.workerSrc = '//mozilla.github.io/pdf.js/build/pdf.worker.mjs'; var pdfDoc = null, pageNum = 1, pageRendering = false, pageNumPending = null, scale = 1.5, canvas1 = document.getElementById('the-canvas-1'), ctx1 = canvas1.getContext('2d'), canvas2 = document.getElementById('the-canvas-2'), ctx2 = canvas2.getContext('2d'); function renderPage(num, canvas, ctx, containerId) { pageRendering = true; pdfDoc.getPage(num).then(function(page) { var viewport = page.getViewport({scale: scale}); canvas.height = viewport.height; canvas.width = viewport.width; var renderContext = { canvasContext: ctx, viewport: viewport, renderInteractive: true }; var renderTask = page.render(renderContext); renderTask.promise.then(function() { pageRendering = false; // 处理页面链接 page.getAnnotations().then(function(annotations) { const container = document.getElementById(containerId); // 清空旧链接元素 while (container.firstChild && container.firstChild !== canvas) { container.removeChild(container.firstChild); } annotations.forEach(function(annot) { if (annot.subtype !== 'Link' || !annot.url) return; // 转换PDF坐标到canvas显示坐标 const rect = annot.rect; const x = rect[0]; const y = viewport.height - rect[3]; const width = rect[2] - rect[0]; const height = rect[3] - rect[1]; // 创建可点击元素 const linkElement = document.createElement('div'); linkElement.style.position = 'absolute'; linkElement.style.left = `${x / viewport.scale}px`; linkElement.style.top = `${y / viewport.scale}px`; linkElement.style.width = `${width / viewport.scale}px`; linkElement.style.height = `${height / viewport.scale}px`; linkElement.style.cursor = 'pointer'; linkElement.style.backgroundColor = 'rgba(0, 128, 255, 0.1)'; // 可选hover提示 linkElement.addEventListener('click', function() { window.open(annot.url, '_blank'); }); container.appendChild(linkElement); }); }); if (pageNumPending !== null) { renderPage(pageNumPending, canvas, ctx, containerId); pageNumPending = null; } }); }); } function queueRenderPage(num) { if (pageRendering) { pageNumPending = num; } else { renderPage(num, canvas1, ctx1, 'canvas-container-1'); if (num < pdfDoc.numPages) { renderPage(num + 1, canvas2, ctx2, 'canvas-container-2'); } updatePageNum(); } } function updatePageNum() { document.getElementById('page_num').textContent = pageNum + ' - ' + (pageNum + 1); } function onPrevPage() { if (pageNum <= 1) return; pageNum -= 2; queueRenderPage(pageNum); } document.getElementById('prev').addEventListener('click', onPrevPage); function onNextPage() { if (pageNum >= pdfDoc.numPages - 1) return; pageNum += 2; queueRenderPage(pageNum); } document.getElementById('next').addEventListener('click', onNextPage); pdfjsLib.getDocument(url).promise.then(function(pdfDoc_) { pdfDoc = pdfDoc_; document.getElementById('page_count').textContent = pdfDoc.numPages; queueRenderPage(pageNum); }); </script> <div> <button id="prev">Previous</button> <button id="next">Next</button> <span>Page: <span id="page_num"></span> / <span id="page_count"></span></span> </div> <div style="display: flex; justify-content: space-between;"> <div id="canvas-container-1" style="width: 50%; position: relative;"> <canvas id="the-canvas-1" style="width: 100%;"></canvas> </div> <div id="canvas-container-2" style="width: 50%; position: relative;"> <canvas id="the-canvas-2" style="width: 100%;"></canvas> </div> </div>
内容的提问来源于stack exchange,提问作者Lukas007
相关产品推荐
相关产品推荐

