參考相關文章:
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')
})
}
