最近做項目中,🈶️遇到過實現模版打印功能,網上也找到很多資料可以實現,有的方式可以實現分頁,但是打印的A4紙上下不能留邊距,后來找到一個通過剪裁的方式可以實現左右上下留邊距,並且能實現分頁;
方法如下:基本思路是對獲得的canvas進行切割,按A4紙大小並留邊距后的比例進行剪裁,切出一頁一頁的內容來,再分別加到pdf中。
DEMO:此方法也可自定義打印的寬高
1 // 導出頁面為PDF格式 2 import html2canvas from "html2canvas" 3 import JSPDF from "jspdf" 4 export default { 5 install(Vue, options) { 6 /** 7 * printId @String 打印區域id 8 * isTemplateIframe @Boolean 打印區域是否是template 9 * printW @Number 打印紙張寬 10 * printH @Number 打印紙張高 11 */ 12 Vue.prototype.ExportSavePdf = function(printId, isTemplateIframe, printW, printH) { 13 return new Promise((resolve, reject) => { 14 let dom; 15 // let iframes; 16 let templateIframeContent; 17 if (isTemplateIframe) { 18 document.getElementById(printId).contentWindow.postMessage("getIframeContent", "*"); 19 window.addEventListener("message", (e) => { 20 // eslint-disable-next-line no-prototype-builtins 21 if (e.data.hasOwnProperty("templateIframe")) { 22 const data = e.data["templateIframe"]; 23 const dataDOM = new DOMParser().parseFromString(data, "text/html"); 24 templateIframeContent = dataDOM.documentElement; 25 } 26 }); 27 setTimeout(() => { 28 if (templateIframeContent) { 29 // dom = document.getElementById(printId).contentWindow.document.querySelector(".flex-container"); 30 dom = templateIframeContent.querySelector(".flex-container"); 31 // iframes = document.getElementById(printId).contentWindow.document.getElementsByTagName("iframe"); 32 // print(dom, iframes); 33 print(dom); 34 } 35 }, 1000) 36 } else { 37 dom = document.getElementById(printId); 38 // iframes = document.getElementsByTagName("iframe"); 39 // print(dom, iframes); 40 print(dom); 41 } 42 43 function print(dom) { 44 const copyDom = dom.cloneNode(true); 45 // const copyIframes = copyDom.querySelectorAll("iframe"); 46 47 /* if (iframes && iframes.length > 0) { 48 for (let i = 0; i < iframes.length; i++) { 49 const yushanInputComponent = iframes[i].closest(".YushanInputComponent"); 50 if (yushanInputComponent) { 51 const currentIframe = iframes[i]; 52 const currentIframeContent = currentIframe.contentWindow.document.body; 53 const pNode = copyIframes[i].parentNode; // 移除copyDom下的iframe 54 pNode.removeChild(copyIframes[i]); 55 pNode.appendChild(currentIframeContent); 56 pNode.style.height = iframes[i].scrollHeight + "px"; 57 continue; 58 } 59 const iframeDom = iframes[i].contentWindow.document.querySelector(".flex-container"); 60 const copyIframeDom = iframeDom.cloneNode(true); // 復制iframe 61 const copyIframeNode = copyIframes[i]; 62 const parentNode = copyIframeNode.parentNode; 63 parentNode.removeChild(copyIframeNode); // 移除原有的iframe 64 parentNode.appendChild(copyIframeDom); 65 parentNode.style.height = iframeDom.scrollHeight + "px"; 66 } 67 } */ 68 copyDom.style.height = "auto"; 69 document.body.appendChild(copyDom); 70 html2canvas(copyDom, { 71 logging: false, 72 useCORS: true 73 }).then(function(canvas) { 74 // 判斷瀏覽器內核是否是IE 75 if (!!window.ActiveXObject || "ActiveXObject" in window) { 76 alert('截圖打印暫不支持IE內核瀏覽器,請更換火狐或谷歌chrome內核瀏覽器,360等雙核瀏覽器請切換至極速模式'); 77 return; 78 } 79 80 // var pdf = new JSPDF('p', 'mm', 'a4'); // A4紙,縱向 81 var direction = 'p';// 默認縱向打印 82 var size = 'a4' 83 if (printW && printH) { 84 size = [printW, printH]; 85 if (printW <= printH) { 86 direction = 'p' 87 } else { 88 direction = 'l' 89 } 90 } 91 var pdf = new JSPDF(direction, 'mm', size); // A4紙,縱向 92 var ctx = canvas.getContext('2d'); 93 var a4w = printW ? (printW - 20) : 190; 94 var a4h = printH ? (printH - 20) : 277; // A4大小,210mm x 297mm,四邊各保留10mm的邊距,顯示區域190x277 95 var imgHeight = Math.floor(a4h * canvas.width / a4w); // 按A4顯示比例換算一頁圖像的像素高度 96 var renderedHeight = 0; 97 98 while (renderedHeight < canvas.height) { 99 var page = document.createElement("canvas"); 100 page.width = canvas.width; 101 page.height = Math.min(imgHeight, canvas.height - renderedHeight); // 可能內容不足一頁 102 103 // 用getImageData剪裁指定區域,並畫到前面建立的canvas對象中 104 page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, 105 canvas.height - renderedHeight)), 0, 0); 106 pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / 107 page.width)); // 添加圖像到頁面,保留10mm邊距 108 109 renderedHeight += imgHeight; 110 if (renderedHeight < canvas.height) { 111 pdf.addPage(); 112 } // 若是后面還有內容,添加一個空頁 113 page.remove(); 114 } 115 const link = window.URL.createObjectURL(pdf.output('blob')); 116 window.open(link); 117 document.body.removeChild(copyDom); 118 resolve(); 119 }) 120 } 121 }) 122 } 123 } 124 }
因為項目中打印的可能是iframe區域,也可以是當前窗口的body內,所以前面代碼中有一些對dom的操作,
核心代碼在后半部分;
效果如下: