记一次用jspdf和html2canvas导出pdf分页处理
生活随笔
收集整理的這篇文章主要介紹了
记一次用jspdf和html2canvas导出pdf分页处理
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
首先項目中用的是elementui,需要導出的是一個table和一些固定的頭部信息組成的一個頁面
頁面大概長這樣:
廢話不多說,上代碼,大佬求輕噴~
<script lang="ts"> import { Vue, Component, Prop } from "vue-property-decorator"; import html2Canvas from "html2canvas"; import jsPdf from "jspdf";@Component({ name: "Download2pdf" }) export default class Download2pdf extends Vue {@Prop({ type: Boolean }) plain?: true;@Prop({ type: String }) btnText?: "Download PDF";@Prop({ type: String }) cardId?: ""; //整個dom id@Prop({ type: String }) tableId?: ""; //需要動態計算的dom id@Prop({ type: String }) topFixedId?: ""; //上方固定高度的dom id@Prop({ type: String }) bottomFixedId?: ""; //底部固定高度的dom id@Prop({ type: String }) fileName?: "fileName";private scale = 2;download() {//querySelector("tr") classNameconst trs = (document.getElementById(this.tableId as string) as HTMLElement).querySelectorAll("tr");const fixedWidth = (document.getElementById(this.topFixedId as string) as HTMLElement).offsetWidth;// 28 / 45 margin高度 ---- 固定高度const topFixedHeight =(document.getElementById(this.topFixedId as string) as HTMLElement).offsetHeight + 28;const botFixedHeight =(document.getElementById(this.bottomFixedId as string) as HTMLElement).offsetHeight + 45;// return;html2Canvas(document.getElementById(this.cardId as string) as HTMLElement, {scale: this.scale, // 提升畫面質量,但是會增加文件大小useCORS: true}).then((canvas: any) => {const contentWidth = canvas.width;const contentHeight = canvas.height;console.log(canvas);// console.log("contentWidth",contentWidth) = 2倍的頁面元素寬高//a4紙的尺寸pt [595.28,841.89]const a4Width = 595.28;const a4Height = 841.89;//一頁pdf能顯示多大的canvas元素var pageHeight = (contentWidth / a4Width) * a4Height; // 單位pxconsole.log("pageHeight", pageHeight);//未生成pdf的html頁面高度let leftHeight = contentHeight;//針對單個頁面偏移let position = 0;//針對整個圖片的偏移let hasPos = 0;//html頁面生成的canvas在pdf中圖片的寬高const imgWidth = a4Width;const imgHeight = (a4Width / contentWidth) * contentHeight; //單位ptlet pad = 60; //a4紙上間距60const pad2 = 20; //a4紙下間距20, 為了分頁截取的圖片有上邊距,下面有個15的偏移量const empty = 60; //表格無數據 nodata高度60let dom2a4 = (h: number): number => { // px轉ptreturn (h * this.scale) / (pageHeight / a4Height);};let pt2canvasH = (h: number): number => { //pt轉pxreturn (contentWidth / a4Width) * h;};const topFixedImgHeight = dom2a4(topFixedHeight); //頁面上方固定的高const botFixedImgHeight = dom2a4(botFixedHeight); //頁面下方固定的高const pageData = canvas.toDataURL("image/jpeg", 1.0);let pdf: any = new jsPdf("p", "pt", "a4");//分頁if (leftHeight < pageHeight) {console.log(1);pdf.addImage(pageData, "JPEG", 0, 0, imgWidth, imgHeight);console.log("addImage");} else {console.log(2);let nowH = topFixedImgHeight;for (let i = 0; i < trs.length; i++) {let _h = trs[i].offsetHeight;//當前tr和下一個tr都是空樣式--代表此表格是空, 或者當前tr是空,沒有下一個tr了,也代表此表格是空if (trs[i].className === "" &&((trs[i + 1] && trs[i + 1].className === "") ||i === trs.length - 1)) {_h = _h + empty;}if (nowH + dom2a4(_h) < a4Height - dom2a4(pad + pad2)) {nowH += dom2a4(_h);if (i === trs.length - 1) {if (nowH + botFixedImgHeight > a4Height - dom2a4(pad + pad2)) {let clipImgData = this.cropCanvas(canvas,contentWidth,contentHeight,pt2canvasH(nowH + dom2a4(pad)), //針對整個dom生成的canvas 需要截取的高度pt2canvasH(hasPos) //截取的起始縱坐標位置);pdf.addImage(clipImgData, "JPEG", 0, 15, imgWidth, imgHeight);pdf.addPage();position = nowH + dom2a4(pad);hasPos += position;pdf.addImage(pageData, "JPEG", 0, -hasPos, imgWidth, imgHeight);} else {let clipImgData = this.cropCanvas(canvas,contentWidth,contentHeight,pt2canvasH(nowH + dom2a4(pad) + botFixedImgHeight), //針對整個dom生成的canvas 需要截取的高度pt2canvasH(hasPos) //截取的起始縱坐標位置);pdf.addImage(clipImgData, "JPEG", 0, 15, imgWidth, imgHeight);console.log("addImage");}}} else {position = nowH + dom2a4(pad);let clipImgData = this.cropCanvas(canvas,contentWidth,contentHeight,pt2canvasH(nowH + dom2a4(pad)), //針對整個dom生成的canvas 需要截取的高度pt2canvasH(hasPos) //截取的起始縱坐標位置);pdf.addImage(clipImgData, "JPEG", 0, 15, imgWidth, imgHeight);console.log("addImage");hasPos += position;nowH = dom2a4(_h);console.log(3);pdf.addPage();pad = 0;console.log("addPage");if (i === trs.length - 1) {pdf.addImage(pageData, "JPEG", 0, -hasPos, imgWidth, imgHeight);}}}}pdf.save(`${this.fileName} Payslip.pdf`);});}cropCanvas(canvas: any,contentWidth: any,contentHeight: any,positionTop: any,hasPos: any) {var ctx = canvas.getContext("2d");// 新canvas控件- 保存裁剪后的圖片var newCanvas = document.createElement("canvas");var newCtx: any = newCanvas.getContext("2d");newCanvas.setAttribute("width", contentWidth);newCanvas.setAttribute("height", contentHeight);//導出的pdf默認黑色背景,需要用白色填充newCtx.fillStyle = "#FFFFFF";newCtx.fillRect(0, 0, contentWidth, contentHeight);//hasPos-3 防止截取掉表格title的最上方1pxvar imgRgbData = ctx.getImageData(0, hasPos > 0 ? (hasPos-3) : hasPos, contentWidth, positionTop);console.log("positionTop=", positionTop, " hasPos=", hasPos);// 把裁剪后的像素數據渲染到新canvasnewCtx.putImageData(imgRgbData, 0, 0);// 獲取裁剪后圖片的base64數據var imgBase64 = newCanvas.toDataURL("image/jpeg", 1.0);return imgBase64;} } </script>整體分頁思想是調用cropCanvas函數去動態截取canvas的內容。
tips:為什么要截取呢?因為分頁的時候可能會出現一行文字被截斷了
注意點:
1、截取函數中canvas轉base64時用toDataURL會出現跨域情況,服務端處理一下就好。
2、代碼里面FixHeight都是業務相關布局端固定高度。
3、導入到pdf里面其實每一頁都是一個圖片,是通過putImageData截取的,content高度應該維持不變,否則會出現圖像尺寸拉伸/扁平的情況。
4、代碼注釋都有寫,歡迎交流~
?
總結
以上是生活随笔為你收集整理的记一次用jspdf和html2canvas导出pdf分页处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2018 Machine Learnin
- 下一篇: 微信小程序继续入坑指南