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