使用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 @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的操作,
核心代码在后半部分;
效果如下:
标签:
html2canvas
, jspdf
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义