html2canvas + jspdf 實現 html 轉 pdf


在前端開發中, html 轉 pdf 是最常見的需求,實現這塊需求的開發  html2canvas 和 jspdf 是最常用的兩個插件,插件都是現成的,但是有時候用不好,也不出現很多頭疼問題:

1. 生成的 pdf 清晰度不高,比較模糊;

2.多頁 pdf 會出現把內容給分割的情況,特別是文字被分割時,體驗很不友好;

3.頁面較寬或較長時,或出現生成的 pdf 內容不全的情況。

 

如果你在項目中出現以上情況,那么不着急,往下看就對了,下面的代碼統統為你解決了

話不多說,直接上代碼:

 

/*
 * @Description: html 轉為 pdf 並下載
 * @Author: cmyoung
 * @Date: 2018-08-10 19:07:32
 * @LastEditTime: 2019-08-23 16:34:18
 */

/**
 * @param html { String } DOM樹
 * @param isOne { Boolean }  是否為單頁 默認 否(false)
 * @return 文件 {pdf格式}
 */

'use strict'
import * as jsPDF from 'jspdf'
import html2canvas from 'html2canvas'

export default async (html, isOne) => {
  let contentWidth = html.clientWidth // 獲得該容器的寬
  let contentHeight = html.clientHeight // 獲得該容器的高
  let canvas = document.createElement('canvas')
  let scale = 2  // 解決清晰度問題,先放大 2倍

  canvas.width = contentWidth * scale // 將畫布寬&&高放大兩倍
  canvas.height = contentHeight * scale
  canvas.getContext('2d').scale(scale, scale)

  let opts = {
    scale: scale,
    canvas: canvas,
    width: contentWidth,
    height: contentHeight,
    useCORS: true
  }

  return html2canvas(html, opts).then(canvas => {
    let pageData = canvas.toDataURL('image/jpeg', 1.0) // 清晰度 0 - 1
    let pdf

    if (isOne) {
      // 單頁
      console.log(contentWidth, 'contentWidth')
      console.log(contentHeight, 'contentHeight')

      // jspdf.js 插件對單頁面的最大寬高限制 為 14400
      let limit = 14400

      if (contentHeight > limit) {
        let contentScale = limit / contentHeight
        contentHeight = limit
        contentWidth = contentScale * contentWidth
      }

      let orientation = 'p'
      // 在 jspdf 源碼里,如果是 orientation = 'p' 且 width > height 時, 會把 width 和 height 值交換,
      // 類似於 把 orientation 的值修改為 'l' , 反之亦同。
      if (contentWidth > contentHeight) {
        orientation = 'l'
      }

      // orientation Possible values are "portrait" or "landscape" (or shortcuts "p" or "l")
      pdf = new jsPDF(orientation, 'pt', [contentWidth, contentHeight]) // 下載尺寸 a4 紙 比例

      // pdf.addImage(pageData, 'JPEG', 左,上,寬度,高度)設置
      pdf.addImage(pageData, 'JPEG', 0, 0, contentWidth, contentHeight)
}
else { //一頁 pdf 顯示 html 頁面生成的 canvas高度 let pageHeight = (contentWidth / 552.28) * 841.89 //未生成 pdf 的 html頁面高度 let leftHeight = contentHeight //頁面偏移 let position = 0 //a4紙的尺寸[595.28,841.89],html 頁面生成的 canvas 在pdf中圖片的寬高 let imgWidth = 555.28 let imgHeight = (imgWidth / contentWidth) * contentHeight pdf = new jsPDF('', 'pt', 'a4') // 下載尺寸 a4 紙 比例 //有兩個高度需要區分,一個是html頁面的實際高度,和生成pdf的頁面高度(841.89) //當內容未超過pdf一頁顯示的范圍,無需分頁 if (leftHeight < pageHeight) { pdf.addImage(pageData, 'JPEG', 20, 0, imgWidth, imgHeight) } else { while (leftHeight > 0) { pdf.addImage(pageData, 'JPEG', 20, position, imgWidth, imgHeight) leftHeight -= pageHeight position -= 841.89 //避免添加空白頁 if (leftHeight > 0) { pdf.addPage() } } } } return pdf }) }

 

以上方法支持,生成的 pdf 為 單頁或多頁可選,如果不是需求必須是多頁的,建議都選擇生成 單頁的,為什么呢?

因為單頁不會出現內容或文字分割的情況。

但是,如果內容過長超過 14400 的話,那么你會發現 14400 之外的內容獲取不到了,這是為什么呢?看來 jspdf 的源碼之后找到答案,源碼里面有限制:

 

 

 不過,我的代碼里已經解決過長的問題(寬度一般不會超過,特殊場景暫不考慮),超過 14400 時,按照高度就為 14400 來算縮放比例,寬度按比例縮放好像就行了,這就完事了?

不不不,好像還有坑,就是 orientation ,有兩個值 "portrait" or "landscape",默認是 'p', 當 orientation = 'p' 且 width > height 時, 他默認會把 width 和 height 值交換,如果你不想要他交換,那么當你的 width > height 時,你把 orientation 動態改為 'l' 即可,反之亦然。

 

 

 

以上希望對你有用,謝謝!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM