如何在React JS中从列表数据生成多页PDF并实现一键批量打印
React 批量生成多份PDF并一键打印实现方案
前置准备
你已经实现的单条数据生成PDF逻辑可以直接复用,目前社区常用的PDF生成方案为@react-pdf/renderer或jsPDF + html2canvas,以下逻辑对两种方案都兼容。
步骤1:批量生成多份PDF
首先维护选中项的状态,全选时将所有列表数据存入选中数组,复用单PDF生成逻辑遍历生成所有PDF文件:
// 假设你已经封装了单条数据生成PDF的方法,入参为单条列表项,返回PDF的Blob对象 import { generateSinglePdf } from './your-existing-pdf-util'; // 批量生成PDF方法 const generateAllSelectedPdfs = async (selectedList) => { const pdfTasks = selectedList.map(async (item) => { const pdfBlob = await generateSinglePdf(item); return { blob: pdfBlob, name: `report-${item.id}.pdf` // 自定义每份PDF的文件名 } }); // 等待所有PDF生成完成,返回Blob数组 return Promise.all(pdfTasks); };
如果你使用@react-pdf/renderer,generateSinglePdf的逻辑可以参考:
import { pdf } from '@react-pdf/renderer'; import SinglePdfTemplate from './SinglePdfTemplate'; // 你已有的单PDF组件 const generateSinglePdf = async (item) => { return pdf(<SinglePdfTemplate data={item} />).toBlob(); };
步骤2:实现一键打印功能
推荐使用合并PDF为单个文件后打印的方案,仅触发一次打印弹窗,用户体验更好,可规避浏览器拦截多次弹窗的问题:
import { PDFDocument } from 'pdf-lib'; // 用于合并PDF的依赖 // 合并多个PDF Blob为单个Blob const mergePdfBlobs = async (pdfBlobList) => { const mergedPdf = await PDFDocument.create(); for (const blob of pdfBlobList) { const pdfBytes = await blob.arrayBuffer(); const currentPdf = await PDFDocument.load(pdfBytes); const pages = await mergedPdf.copyPages(currentPdf, currentPdf.getPageIndices()); pages.forEach(page => mergedPdf.addPage(page)); } const mergedBytes = await mergedPdf.save(); return new Blob([mergedBytes], { type: 'application/pdf' }); }; // 一键打印入口方法 const handlePrintAll = async (selectedList) => { // 加loading状态的逻辑可以自行补充 const pdfList = await generateAllSelectedPdfs(selectedList); const mergedPdfBlob = await mergePdfBlobs(pdfList.map(item => item.blob)); // 触发打印 const pdfUrl = URL.createObjectURL(mergedPdfBlob); const printWindow = window.open(pdfUrl, '_blank'); printWindow.onload = () => { printWindow.print(); // 打印完成后释放资源 printWindow.onfocus = () => { URL.revokeObjectURL(pdfUrl); printWindow.close(); }; }; };
如果你不需要合并文件,也可以选择依次打印单份PDF,该方案会多次触发打印弹窗,仅适合小批量场景:
const handlePrintAllSequentially = async (selectedList) => { const pdfList = await generateAllSelectedPdfs(selectedList); for (const pdfItem of pdfList) { const pdfUrl = URL.createObjectURL(pdfItem.blob); const printWindow = window.open(pdfUrl, '_blank'); // 等待当前PDF打印完成再处理下一份 await new Promise(resolve => { printWindow.onload = () => { printWindow.print(); printWindow.onfocus = () => { URL.revokeObjectURL(pdfUrl); printWindow.close(); resolve(); }; }; }); } };
注意事项
- 数据量较大时建议添加loading状态和进度提示,避免用户误判页面卡顿
- 必须调用
URL.revokeObjectURL释放生成的临时URL,避免内存泄漏 - 如果需要批量下载所有PDF,可以配合
jszip将所有Blob打包为Zip文件下载
内容的提问来源于stack exchange,提问作者faysal neowaz
相关产品推荐
相关产品推荐

