如何在 jsPDF 中使用 addHTML 方法为所有 PDF 页面添加页眉和页脚

9
我正在使用jspdf将HTML转换为PDF。我使用addHTML方法将HTML页面转换为PDF。
  var htmlSource = $('#body')[0];

 function crate (){
   var pdf = new jsPDF('p','px');

  pdf.addHTML(
    htmlSource,10, 10, {pagesplit: true, margin: {top: 10, right: 10,bottom: 10, left: 10, useFor: 'page'}},
    function(dispose){
       pdf.save('datapdf.pdf');
    }
  );

我希望在所有页面上添加头部和底部,不过对于头部和底部,我仅想在第一页上留出空白。但是目前的选项只能在第一页上留出头部空白。


1
我在你之前尝试了很多次,然后得到了这个结果,请查看这个问题:https://stackoverflow.com/questions/47435088/convert-html-to-pdf-with-images - E-housma Mardini
你尝试过添加HTML头部和尾部标签吗? - vahdet
@vahdet 是的,我在HTML中添加了<header><span>测试</span></header>和<footer></footer>标签。 - Viijay ijardar
@E-housmaMardini 我的代码在转换成PDF时工作正常,但我想在所有PDF页面上添加页眉和页脚。 - Viijay ijardar
如果发现任何问题,请让我知道。 - E-housma Mardini
显示剩余2条评论
6个回答

6
一种方法是在客户端浏览器中重新填充HTML页面呈现,以便按照您想要的方式显示在PDF中(然后只需使用上面创建的函数),因此格式由一系列垂直元素组成,如h、p1、f、h、p2、f、h、p3、f等(其中h=头部,p1 ... pn是页面,f=页脚),而不是一个仅包含h、p1、p2、p3、...、pn、f的系列(目前就是这样)。
这意味着您可能可以访问HTML页面的源代码(因此它不仅仅是从互联网获取的页面),因为如果它是外部资源,则标题和页脚的尺寸可能是以编程方式构建的,以便与页面的其他元素相关联(我认为这里考虑的是灵活性/垂直应用/或网格技术在呈现网页时)。
另一个方面,如果采用此方法,可能内容的分割并不总是可能的(我不是在这里考虑破坏表格或其他多页元素,仅当使用滚动时可见),但是渲染也可能考虑页面的垂直显示(与桌面上的横向模式相反)以重新绘制页面中的元素。有时页脚和页眉可能会变大,因此我不确定为什么您要花费最终打印页面的宝贵空间的一部分来做这件事。(解决方案可能是打开一个新窗口,然后在现有页面之后重新呈现该页面以新格式,然后启动打印确认/下载文件/关闭相应页面之前。)
另一种方法是更改函数以便使用页面的虚拟呈现(无显示页面)-通过对函数进行更改而不是在呈现本身中进行更改。
但是,这第二种方法也存在一些挑战。最初,在声明变量'var pdf'时,它被创建为唯一的数据存储容器,然后将构造函数分配给它(var pdf = new jsPDF('p','px');)。但是在下一步中,您将HTML内容添加到其中(pdf.addHTML),这是单个元素,而不是多个实体。您应该更改函数以使其打印数组,其中您首先根据渲染的页面尺寸计算元素。
也许代码会变成:
var fullpage, onepage, headd, foott, edges, contentt, he, fo, c, pages;
fullpage = document.body.scrollHeight; // height of all html page (not just the visible content)
onepage = 1200; // height of each single page printed in pdf - in pixels
headd = document.getElementById("header");
he =  headd.offsetHeight;
foott = document.getElementById("footer"); 
fo = foott.offsetHeight;
edges = he + fo;
contentt = onepage - edges; // height of content of each page printed

pages = [0];  // start to work with first page which obviously is there
fullpage -= onepage; // remove height of first printed page (containg both header and footer)
    pdf.addHTML( // create first page of pdf file
    htmlSource, 10, 10, {pagesplit: true, margin: {top: 10, right:
      10, bottom: 10, left: 10, useFor: 'page'}},
    function(dispose){
       pdf.save('datapdf.pdf');
    });   // this is your code

var i = 0; // start the counter

 while(fullpage > 0) { // start adding header + footer to remaining pages
  fullpage += edges; // if there is still a page 2...n we add edges, etc.
  i++;
  pages[i] = content(onepage) { // here you must insert the code for harvesting the n-st page content from your source code
    return htmlSource;
  }
     function addPages(i) {
         var eachpdf = "datapdf" + i + ".pdf";
          // <= here goes again your code, with a small change
          // pagesplit: false - instead of true, in order to speed the process, and also
          // pdf.save(eachpdf); - instead of pdf.save('datapdf.pdf');              
     }
 }

你要做的是创建一个包含一系列he、p1、fo、he、p2、fo、he、p3、fo等页面(其中he=头部,p1 ... pn为各个页面/上面命名为datapdfi/,fo=页脚),而不是包含只有h、p1、p2、p3、... ,pn、f的页面序列。
这意味着你必须构建一个包含单独pdf页面的数组,如上述代码所述。
我还没有为你创建分离每个页面内容的代码(可能返回htmlSource),但这与页面呈现方式紧密相关。

4
如果有人仍在寻找简短的解决方案,您可以尝试以下方法:
对于页脚中的页码,

html2pdf().from(element).set(opt).toPdf().get('pdf').then(function (pdf) {
  var totalPages = pdf.internal.getNumberOfPages();

  for (i = 1; i <= totalPages; i++) {
    pdf.setPage(i);
    pdf.setFontSize(10);
    pdf.setTextColor(150);
    pdf.text('Page ' + i + ' of ' + totalPages, pdf.internal.pageSize.getWidth() - 100, pdf.internal.pageSize.getHeight() - 30);
  } 
}).save();

关于标题,您可以编写

pdfObject.text("my header text", 10, 10)

这将在每个页面的位置x=10,y=10创建标题文本为我的标题文本

我遇到了一个错误:未捕获的缺少源元素或字符串。 - Naren Verma

3

有一种建议的方法是使用HTML的元素<header><footer>来实现这个目的,例如:

<footer>
    <div style='text-align:center;'>Page <span class="pageCounter"></span>/<span class="totalPages"></span></div>
</footer>

请查看 https://github.com/MrRio/jsPDF/pull/260


1
@sajeentharan 头部和底部标签已经在HTML中,但并未显示在所有页面上。 - Viijay ijardar

2
let doc = new JsPDF('p', 'pt', 'a4')
    doc.html(componentRef.current, {
        callback: function (pdf) {
            //pdf.setFontSize(10)
            let totalPages = pdf.internal.pages.length-1
            for (let i = 1; i <= totalPages; i++) {
                pdf.setPage(i);
                // pdf.setFontSize(10);
                // pdf.setTextColor(150);
                pdf.text('Page ' + i + ' of ' + totalPages, pdf.internal.pageSize.getWidth() - 100, pdf.internal.pageSize.getHeight() - 30);
            }
            pdf.save(
                `delivery-${deliveryDate}.pdf`
            )
        },
        margin: [10, 0, 55, 0],
        autoPaging: "text",
    })

请在您的答案中添加文字说明。 - Lajos Arpad

1
在React中,你可以做以下操作:
检查this 官方仓库以更改 jspdf-autotable 生成器类。
此外,你可以使用标题图像,但需要将其转换为base64格式。Convert 图像为 base64 在线服务。
还可以使用我的PDF类来使用TypeScript生成一个具有js-pdf和autotable插件的适当PDF报告:
import jspdf from "jspdf";
import autoTable from "jspdf-autotable";

// Main assets of our custom jspdf.
// It's very important to import this font assets.
import CustomPDFFont from "../assets/make_pdf_assets/Font";
import CustomHeadingImg from "../assets/make_pdf_assets/HeadingImage";
import colors from "../config/colors";

export default class ExportPdf {
  document: any;
  isValueAdded: boolean;
  pageSize: any;
  pageHeight: any;
  pageWidth: any;
  createdAt: string;

  constructor() {
    this.isValueAdded = false;

    this.document = new jspdf("p", "px");
    this.document.addFileToVFS("font_name.ttf", CustomPDFFont);
    this.document.addFont(
      "font_name.ttf",
      "font_face_name",
      "normal"
    );
    this.document.setFont("font_face_name");

    // jsPDF 1.4+ uses getWidth, <1.4 uses .width
    this.pageSize = this.document.internal.pageSize;
    this.pageHeight = this.pageSize.height
      ? this.pageSize.height
      : this.pageSize.getHeight();

    this.pageWidth = this.pageSize.width
      ? this.pageSize.width
      : this.pageSize.getHeight();


    this.createdAt = "Mamad Steve";
  }

  /** Set header Logo */
  private _setHeaderLogo = (data: any) => {
    this.document.addImage(
      CustomHeadingImg, // Use base64 format
      "png",
      data.settings.margin.left,
      20, // Y distance
      70, // Width size
      20 // Height size
    );
  };

  /** Set date and time of exported report */
  private _setDateTime = () => {
    const date: Date = new Date();

    // Set date time at header
    let reportDate: string = [
      date.getFullYear(),
      date.getMonth(),
      date.getDay(),
    ].toString();

    let reportTime: string = [
      date.getHours(),
      date.getMinutes(),
      date.getSeconds(),
    ].toString();

    // Makes DateTime more readable: Date: 11/6/2023 Time: 11:25
    reportDate = reportDate.replaceAll(",", "/");
    reportTime = reportTime.replaceAll(",", ":");

    this.document.setFontSize(10);
    this.document.text(
      `Date: ${reportDate} Time: ${reportTime}`,
      this.pageWidth - 140,
      50,
    );
  };

  /** Set page number at footer */
  private _setPageNum = (data: any) => {
    // Set number in Footer of every page
    const content = "Page " + this.document.internal.getNumberOfPages();
    this.document.setFontSize(10);

    this.document.text(
      `${content}, By ${this.createdAt}`,
      data.settings.margin.left,
      this.pageHeight - 10
    );
  };

  /**
   * # Make custom `.pdf`
   *
   * Make custom `pdf` with **Grid** style, custom header with logo image,
   * custom footer with page number.
   *
   * @param any[] data
   * @param any[] columns
   *
   * @example
   *
   * const data = [["data0", "data1", "data2", ...], [...], ...]
   * const column = ["field0", "field1", "field2", ...];
   *
   * this.addNewTableInPdf(data: data, columns: columns);
   * */
  public addNewTableInPdf = (data: any[], columns: any[]): void => {
    autoTable(this.document, {
      head: columns,
      body: data,
      theme: "grid",
      styles: { font: "font_face_name", halign: "center" },
      didDrawPage: (data) => {
        /** At Header */
        this._setHeaderLogo(data);
        this._setDateTime();
        /** At Footer */
        this._setPageNum(data);
      },
      headStyles: { fillColor: colors.primary, textColor: "#fff" },
      margin: { top: 50 },
    });
  };
}

这个类是我自己写的,它运行良好,但可能对其他开发人员来说不够简洁。但结果是: 输入图片描述

0
pdf()
  {
    var margin= [9,9,9,9];
    var ptbdel=11;
    var rem=0;
    var invoiceNumber= this.orderDetail.invoiceNumber;
    var count =this.orderDetail.orderItems.length;
    debugger
    if(count>3)
    {
        margin=[10, 10, 10, 10]
        ptbdel=12;
    }
    var doc = new jsPDF('l','mm',"a4",);
    doc.html(document.getElementById('contentpopup')!, {
      autoPaging:"text",      
      callback: function (doc) {
      
        let i=doc.internal.pages.length-1
      rem=i-ptbdel;
      while(i>=(rem))
      {
        doc.deletePage(i)
        i--;
      }
        for(let i = 1 ; i<=doc.internal.pages.length;i++)
      {
        doc.setPage(i)
        doc.setFontSize(8)
        doc.text("Page "+doc.getCurrentPageInfo().pageNumber+" of "+(rem-1),270,5)
      }

      doc.save(invoiceNumber+'.pdf');
  },
      margin: margin,
      html2canvas: {
        
          scale: .25, //you have to adjust to your size
      },    
    });
}

Adjust Scale That Best Fits in Your Scenario.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接