“在日常前端开发或调试中,我们经常会遇到网页内嵌的 PDF 预览组件(通常基于 PDF.js )存在‘打印截断’或‘长图预览不全’的问题。这是因为组件为了性能,采用了懒加载(Lazy Loading),导致浏览器原生打印或另存时只能截取当前可视区域。”
01
—
核心代码
async function extractPdfData(){try{// 1. 获取 iframe 及其 window 对象const iframe = document.querySelector('iframe');if (!iframe?.contentWindow) throw new Error("未找到 iframe 或存在跨域限制");// 2. 获取 PDF.js 全局实例const viewerApp = iframe.contentWindow.PDFViewerApplication;if(!viewerApp?.pdfDocument) throw new Error("PDF 实例未初始化");// 3. 核心:调用 getData() 获取完整的 PDF 字节数组 (Uint8Array)const pdfData = await viewerApp.pdfDocument.getData();// 4. 构建 Blob 并生成临时下载链接const blob =new Blob([pdfData],{ type:'application/pdf'});const url = URL.createObjectURL(blob);// 5. 模拟点击触发下载const link = document.createElement('a');link.href = url;link.download ='extracted_document.pdf';document.body.appendChild(link);link.click();// 6. 清理 DOM 与释放内存 (防止内存泄漏)document.body.removeChild(link);setTimeout(()=> URL.revokeObjectURL(url),1000);console.log("数据提取成功");}catch(e){console.error("提取失败:", e.message);}}extractPdfData();
02
—
- 同源策略与 iframe 穿透:通过
document.querySelector('iframe').contentWindow拿到内嵌文档的 window 对象。前提是主站与 iframe 满足同源策略,否则会报跨域错误。 - 直取内存数据:
PDFViewerApplication是 PDF.js 暴露的全局入口。调用 pdfDocument.getData()可以直接拿到未经任何裁剪的原始Uint8Array字节流,完美避开 Canvas 懒加载导致的视口截断问题。 - Blob 与内存管理:使用
URL.createObjectURL生成下载链接。关键点:下载完成后必须调用 URL.revokeObjectURL释放内存,否则在单页应用(SPA)中极易造成内存泄漏。
03
—
本文代码及技巧仅用于前端底层技术(iframe 通信、PDF.js 架构、内存管理)的交流与学习研究。
请勿将此技术用于任何未经授权的系统测试或商业牟利。
尊重知识产权。日常办公学习中,获取或离线阅读各类文档资料,请务必使用官方提供的正规渠道或官方客户端,以获得最安全稳定的体验。作者不对代码的衍生使用行为承担任何责任。
参考文档:
[1] PDF.js 官方项目:
[2]数据获取接口:pdfDocument.getData() 接口的标准说明,用于从内存提取原始 Uint8Array 字节流。
[3]内存对象转换:URL.revokeObjectURL() 释放内存。
[4]安全边界机制:iframe 调试时的安全拦截机制(即代码中 contentWindow 的跨域防护)。
夜雨聆风