You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 10:36:01