如何实现点击打印按钮时同时打印嵌入PDF及页面内容?
同步打印页面内容与嵌入PDF的可行实现
首先明确一个硬限制:如果嵌入的PDF和当前页面跨域,所有前端方案都无法实现一次性合并打印,这是浏览器同源策略的安全规则,没有绕过空间,这种情况要么让后端把PDF代理到同域,要么只能接受分两次打印。
绝大多数人实现失败的核心原因,是直接用<embed>/<object>/<iframe>调用浏览器自带的PDF预览插件:这部分内容是浏览器独立进程渲染的插件层,根本不在当前页面的DOM流里,原生window.print()捕获不到插件层的内容,自然没法和页面上的标题、正文拼到一起打印。
兼容性最好的实现方案(推荐)
直接用pdf.js把PDF渲染成页面内的canvas元素,让PDF内容成为普通DOM的一部分,配合打印样式就能一次性输出所有内容,全主流浏览器兼容,不会弹出两次打印窗口。
- 移除原有的原生PDF嵌入控件,引入pdf.js后把PDF逐页渲染到指定容器中,渲染完成的内容就是普通canvas标签,和页面上的标题、正文属于同一DOM树,可以被打印逻辑正常捕获。
- 编写
@media print专用打印样式,把打印时不需要的元素(打印按钮、导航栏、悬浮组件等)全部隐藏,给渲染PDF的canvas添加分页规则,避免内容被页边距截断。 - 给打印按钮绑定点击事件,直接调用
window.print()即可,如果有临时调整布局的需求,监听afterprint事件在打印结束后还原页面状态就行。
核心实现代码参考:
<!-- 基础页面结构 --> <h1>这是页面标题</h1> <div class="main-content">这里是页面正文内容</div> <!-- PDF渲染容器,不要放embed/object/iframe --> <div id="pdf-container"></div> <button id="printBtn">打印</button> <style> /* 打印专用样式 */ @media print { /* 标记了no-print的元素打印时全部隐藏 */ #printBtn, .no-print { display: none !important; } /* 适配PDF画布的打印尺寸,避免模糊和截断 */ #pdf-container canvas { width: 100% !important; height: auto !important; page-break-after: always; } } </style> <script> // 打印按钮绑定事件 document.getElementById('printBtn').addEventListener('click', () => { window.print() }) // 此处补充pdf.js初始化、渲染PDF到#pdf-container的逻辑即可 </script>
折中方案(不想替换原有嵌入方式时使用)
如果一定要保留原生PDF插件的预览效果,只能拆分两次打印任务,缺点是用户会看到两次打印确认弹窗,体验较差,且同样要求PDF资源和页面同域:
document.getElementById('printBtn').addEventListener('click', () => { // 加专属类名,配合打印样式控制当前阶段只显示标题、正文,隐藏PDF嵌入控件 document.body.classList.add('print-text-stage') window.print() window.addEventListener('afterprint', function triggerPdfPrint() { // 第一次打印结束,移除类名,触发PDF插件的打印逻辑 document.body.classList.remove('print-text-stage') const pdfNode = document.getElementById('embeddedPdf') pdfNode.print() window.removeEventListener('afterprint', triggerPdfPrint) }, { once: true }) })
避坑提醒
- 不要尝试抓取iframe内容、跨域postMessage传PDF内容这类偏方,跨域下根本拿不到第三方PDF插件的内部操作权限,完全跑不通。
- 用pdf.js渲染时,渲染分辨率不要低于150dpi,不然打印出来的PDF内容会发虚模糊。
- 如果PDF文件体积很大,渲染canvas的时候记得做懒加载,避免首屏加载卡顿。
内容的提问来源于stack exchange,提问作者Anne K
相关产品推荐
相关产品推荐

