使用html2canvas+jsPDF导出PDF仅显示第一页,如何实现多页渲染?
解决Angular中PDF导出多页渲染的问题
问题分析
你当前的实现是把整个DOM元素转成单张Canvas图片后直接插入PDF,当内容高度超过A4页面高度时,超出部分会被截断,只能显示第一页。要实现多页渲染,需要针对内容高度做分页处理,或者按数据项(每个asset)单独生成页面。
方案一:按每个Asset生成独立页面
你的HTML是循环渲染每个asset,直接为每个资产单独创建PDF页面,逻辑更清晰,每个资产的信息会在独立一页显示:
修改后的导出函数
import jsPDF from 'jspdf'; import html2canvas from 'html2canvas'; export() { const pdfData = new jsPDF('p', 'mm', 'a4'); const imgWidth = 210; const pageHeight = 297; // A4标准高度(毫米) // 获取所有资产对应的DOM容器 const assetElements = document.querySelectorAll('.asset-container'); // 遍历处理每个资产页面 assetElements.forEach(async (element, index) => { // 第一页无需新增,后续资产都新增页面 if (index > 0) { pdfData.addPage(); } const canvas = await html2canvas(element as HTMLElement); let imgHeight = canvas.height * imgWidth / canvas.width; // 处理单资产内容超过一页的情况,缩放适配页面高度 let renderWidth = imgWidth; let renderHeight = imgHeight; let xPosition = 0; if (imgHeight > pageHeight) { const scaleRatio = pageHeight / imgHeight; renderWidth = imgWidth * scaleRatio; renderHeight = pageHeight; xPosition = (210 - renderWidth) / 2; // 水平居中 } pdfData.addImage(canvas.toDataURL('image/png'), 'PNG', xPosition, 0, renderWidth, renderHeight); // 最后一个资产处理完成后保存PDF if (index === assetElements.length - 1) { pdfData.save(`Export${this.selected}.pdf`); } }); }
修改后的HTML结构(给每个资产容器添加类名)
<div *ngFor="let asset of assets" class="asset-container"> <h1 style="text-align: center;">Asset ID {{asset.id}}</h1> <table class="export-items"> <tr> <td>Product:</td><td>{{asset.productOfferName||'N/A'}}</td> </tr> <tr> <td>SA name:</td><td>{{uom.agreementNames[asset.saAgreementId]||asset.saAgreementId||'N/A'}}</td> </tr> <tr> <td>Asset ID:</td><td>{{asset.id||'N/A'}}</td> </tr> <tr *ngIf="asset.serviceLocationId"> <td>Location ID:</td><td>{{asset.serviceLocationId}}</td> </tr> <tr> <td>Order num:</td><td>{{asset.orderNum||'N/A'}}</td> </tr> <tr> <td>Order item num:</td><td>{{asset.orderItemNum||'N/A'}}</td> </tr> <tr> <td>Status:</td><td>{{asset.status||'N/A'}}</td> </tr> <tr> <td>Start date:</td><td>{{asset.serviceStartDate | date:'longDate'}}</td> </tr> <tr> <td>Termination date:</td><td>{{asset.terminationDate ? (asset.terminationDate | date:'longDate') : 'N/A'}}</td> </tr> <tr> <td>Created by:</td><td>{{asset.createdBy||'N/A'}}</td> </tr> <tr> <td>Modified:</td><td>{{asset.modified ? (asset.modified | date:'longDate') : 'N/A'}}</td> </tr> <tr> <td>Modified by:</td><td>{{asset.modifiedBy||'N/A'}}</td> </tr> </table> </div>
方案二:长内容自动分页(单元素内容超一页时)
如果单个资产的内容可能超过一页,需要将Canvas内容切割成多个页面:
export() { const data = document.getElementById('export_pdf'); if (!data) return; html2canvas(data as HTMLElement).then(canvas => { const imgWidth = 210; const pageHeight = 297; const imgHeight = canvas.height * imgWidth / canvas.width; let heightLeft = imgHeight; let position = 0; const contentDataURL = canvas.toDataURL('image/png'); const pdfData = new jsPDF('p', 'mm', 'a4'); // 添加第一页 pdfData.addImage(contentDataURL, 'PNG', 0, position, imgWidth, imgHeight); heightLeft -= pageHeight; // 循环添加剩余页面 while (heightLeft >= 0) { position = heightLeft - imgHeight; pdfData.addPage(); pdfData.addImage(contentDataURL, 'PNG', 0, position, imgWidth, imgHeight); heightLeft -= pageHeight; } pdfData.save(`Export${this.selected}.pdf`); }); }
注意事项
- 确保已正确安装依赖:
npm install html2canvas jspdf - 如果页面包含异步加载内容,需等待内容完全渲染后再执行导出函数
- 可通过调整CSS样式(如边距、字体大小)优化PDF渲染效果
内容的提问来源于stack exchange,提问作者None
相关产品推荐
相关产品推荐

