1. 程式人生 > 實用技巧 >html2canvas+jspdf實現下載pdf檔案

html2canvas+jspdf實現下載pdf檔案

參考相關文章:

https://blog.risingstack.com/pdf-from-html-node-js-puppeteer/

https://juejin.im/post/5dae8b82e51d4524ce222764這篇文章寫得很好很具體了,下面記錄下實際運用。

關於頁面匯出 .pdf 格式檔案:

  使用 window.print() 即可調出瀏覽器的線上列印功能,然後儲存為 pdf 格式的檔案,如果不想在頁面彈出列印功能,可以把生成 pdf 放在後端處理,後端生成好 pdf 格式的檔案,放在伺服器上,然後提供給前端一個 api 地址,前端發起 api 請求去下載 pdf 檔案,大概是這樣的思路。

  但是本文記錄是通過 html2canvas 將 HTML 頁面轉換成圖片,然後通過 jspdf 將圖片的 base64 生成 pdf 檔案。

  程式碼環境:React + ts

  缺點:生成的 pdf 內容無法複製,因為是圖片。

1、安裝html2canvas 和 jspdf :

npm install html2canvas jspdf

2、新建一個檔案,單獨處理生成 pdf

import html2canvas from 'html2canvas'
import jsPdf from 'jspdf'

async function htmlToPdf() {
  const elId: string = 'body' // body: 想要生成 pdf 的頁面的id
  if (!elId) {
    // tslint:disable-next-line:no-console
    console.error('匯出節點不存在!')
    return
  }
  // 將html dom節點生成canvas
  const htmlCanvas = await getCanvasByHtmlId(elId)
  // 將canvas物件轉為pdf
  const pdf = canvasToPdf(htmlCanvas)
  // 通過瀏覽器下載pdf
  downPdf(pdf, '檔名')
}

/**
 *  @param elId 列印的節點ID
 */
async function getCanvasByHtmlId(elId: string) {
  const elIdDom: any = document.getElementById(elId)
  const canvas: any = await html2canvas(elIdDom, {
    scale: 2,
    useCORS: true,
    allowTaint: true,
    // taintTest: false,
    imageTimeout: 0,
  }).then((canvas: any) => {
    return canvas
  })

  return canvas
}

/**
 *  @param htmlCanvas canvas物件
 */
function canvasToPdf(htmlCanvas: any) {
  const canvasWidth = htmlCanvas.width
  const canvasHeight = htmlCanvas.height
  const imgBase64 = htmlCanvas.toDataURL('image/jpeg', 1.0)

  // a4紙的尺寸[595.28,841.89],html頁面生成的canvas在pdf中圖片的寬高
  const imgWidth = 595.28
  // 圖片高度需要等比縮放
  const imgHeight = 595.28 / canvasWidth * canvasHeight

  let pageHeight = imgHeight // pdf轉化後頁面總高度
  let position = 0

  const pdfInstance = new jsPdf('', 'pt', 'a4')
  pdfInstance.setFontSize(12)

  if (imgHeight < 841.89) {
    pdfInstance.addImage(imgBase64, 'JPEG', 0, 0, imgWidth, imgHeight)
  } else {
    while (pageHeight > 0) {
      pdfInstance.addImage(imgBase64, 'JPEG', 0, position, imgWidth, imgHeight)
      pageHeight -= 841.89
      position -= 841.89
      if (pageHeight > 0) {
        pdfInstance.addPage()
      }
    }
  }

  return pdfInstance
}

function downPdf(pdfInstance: any, title: string) {
  // 檔名過長導致下載失敗
  if (title.length > 50) {
    title = title.substring(title.length - 50)
  }

  pdfInstance.save(title + '.pdf', { returnPromise: true }).then(() => {
    // 搜狗瀏覽器下載機制問題暫時不關閉
    if (!(navigator.userAgent.toLowerCase().indexOf('se 2.x') > -1)) {
      setTimeout(window.close, 300)
    }
  })
}

export default htmlToPdf

  

3、在頁面呼叫

import HtmlToPdf from './HtmlToPdf'


 <div onClick={HtmlToPdf}>下載</div>

  

補充:

  其實還有另外一種方法更簡便,但是缺點是無法等比縮放 pdf 的寬高度。你也可以結合上面的方法計算出等比縮放的寬和高。

function printPDF () {
    const domElement: any = document.getElementById('body')
    html2canvas(domElement, { onclone: () => {
    }})
    .then((canvas: any) => {
        const img = canvas.toDataURL('image/png')
        const pdf = new jsPdf()
        pdf.addImage(img, 'JPEG', 0, 0, 230, 200) // 230, 200 自定義的
        pdf.save('your-filename.pdf')
    })
  }