使用html2canvas和jsPdf实现打印功能
最近做项目中,???遇到过实现模版打印功能,网上也找到很多资料可以实现,有的方式可以实现分页,但是打印的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 打印区域id 8 * isIframe 打印区域是否是iframe 9 * childiframeIds 打印区域内包含的iframe的id 10 */ 11 Vue.prototype.ExportSavePdf = async function (printId, isIframe, childiframeIds) { 12 let dom; 13 if (isIframe) { 14 dom = document.getElementById(printId).contentWindow.document.querySelector(".flex-container") 15 } else { 16 dom = document.getElementById(printId); 17 } 18 let copyDom = dom.cloneNode(true); 19 if (childiframeIds && childiframeIds.length > 0) { 20 childiframeIds.forEach((fId) => { 21 let iframeDom = document.getElementById(fId).contentWindow.document.querySelector(".flex-container"); 22 let copyIframeDom = iframeDom.cloneNode(true); // 复制iframe 23 let copyIframeNode = copyDom.querySelector(`#${fId}`); 24 let parentNode = copyIframeNode.parentNode; 25 parentNode.removeChild(copyIframeNode); // 移除原有的iframe 26 parentNode.appendChild(copyIframeDom); 27 parentNode.style.height = iframeDom.scrollHeight + "px"; 28 }) 29 } 30 copyDom.style.height = "auto"; 31 document.body.appendChild(copyDom); 32 /* const [lWidth, rWidth] = [20, 20]; 33 const pageWidth = 595.28 - lWidth - rWidth // A4纸的宽高 减去左右边距 34 const pageHeight = 841.89 */ 35 // a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高 36 await html2canvas(copyDom, { 37 logging: false, 38 width: dom.scrollWidth, 39 height: dom.scrollHeight, 40 windowWidth: dom.scrollWidth, 41 windowHeight: dom.scrollHeight 42 }).then(function (canvas) { 43 // 判断浏览器内核是否是IE 44 if (!!window.ActiveXObject || "ActiveXObject" in window) { 45 alert('截图打印暂不支持IE内核浏览器,请更换火狐或谷歌chrome内核浏览器,360等双核浏览器请切换至极速模式'); 46 return; 47 } 48 49 /* const contentWidth = canvas.width 50 const contentHeight = canvas.height 51 const pageData = canvas.toDataURL('image/jpeg/png', 1) 52 const PDF = new JSPDF('', 'pt', 'a4') // , true 53 54 // canvas图片的高 55 const imgHeight = pageWidth / contentWidth * contentHeight // canvas的宽与PDF的宽比列一样的时候,canvas的高缩放后的值 56 let leftHeight = imgHeight 57 let position = 0 58 // 如果图片的高小于A4纸的高,不分页 59 if (leftHeight < pageHeight) { 60 PDF.addImage(pageData, 'JPEG', lWidth, 0, pageWidth, imgHeight) 61 } else { 62 // 分页 63 // let index = 0 64 while (leftHeight > 0) { 65 PDF.addImage(pageData, 'JPEG', lWidth, position, pageWidth, imgHeight) 66 leftHeight = leftHeight - pageHeight 67 position -= pageHeight 68 if (leftHeight > 0) { 69 PDF.addPage() 70 } 71 } 72 } 73 const link = window.URL.createObjectURL(PDF.output('blob')); 74 window.open(link); 75 document.body.removeChild(copyDom); */ 76 // const myWindow = window.open(link); 77 // myWindow.print(); 78 79 var pdf = new JSPDF('p', 'mm', 'a4'); // A4纸,纵向 80 var ctx = canvas.getContext('2d'); 81 var a4w = 190; 82 var a4h = 277; // A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277 83 var imgHeight = Math.floor(a4h * canvas.width / a4w); // 按A4显示比例换算一页图像的像素高度 84 var renderedHeight = 0; 85 86 while (renderedHeight < canvas.height) { 87 var page = document.createElement("canvas"); 88 page.width = canvas.width; 89 page.height = Math.min(imgHeight, canvas.height - renderedHeight); // 可能内容不足一页 90 91 // 用getImageData剪裁指定区域,并画到前面建立的canvas对象中 92 page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, 93 canvas.height - renderedHeight)), 0, 0); 94 pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / 95 page.width)); // 添加图像到页面,保留10mm边距 96 97 renderedHeight += imgHeight; 98 if (renderedHeight < canvas.height) { pdf.addPage(); } // 若是后面还有内容,添加一个空页 100 page.remove(); 101 } 102 const link = window.URL.createObjectURL(pdf.output('blob')); 103 window.open(link); 104 document.body.removeChild(copyDom); 105 }) 106 } 107 } 108 }
因为项目中打印的可能是iframe区域,也可以是当前窗口的body内,所以前面代码中有一些对dom的操作,
核心代码在后半部分;
效果如下: