前端 jsPDf和html2canvans html转化pdf
1.html转化为pdf过程
html2canvas(element, { dpi: 120, // 图片清晰度问题 }).then(canvas => { let contentWidth = canvas.width // 画布的宽度 let contentHeight = canvas.height // 画布的高度 let pageHeight = contentWidth / 592.28 * 841.89 // 每一页的高度 let leftHeight = contentHeight // 偏移的位置 let position = 0 let imgWidth = 595.28 let imgHeight = 592.28 / contentWidth * contentHeight let pageData = canvas.toDataURL('image/jpeg', 1.0) let PDF = new jsPDF('', 'pt', 'a4') PDF.text(100, 100, '设置的表头的参数') let pageArr = [] // if (leftHeight < pageHeight) { // PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight) // } else { // while (leftHeight > 0) { // PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight) // leftHeight -= pageHeight // position -= 841.89 // pageArr.push(position) // console.log('打印的页码数是多少', position) // if (leftHeight > 0) { // PDF.addPage() // } // } // } PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, 5000) console.log('打印页码数', pageArr) pageArr.forEach((val,index) => { console.log('循环的数组', index) }) PDF.save('api.pdf') })
上述过程会导致 内容截断
代码修改一:整体一页 不分页
html2canvas(element, { allowTaint: true, scale: 2 // 提升画面质量,但是会增加文件大小 }).then(function (canvas) { /**jspdf将html转为pdf一页显示不截断,整体思路: * 1. 获取DOM * 2. 将DOM转换为canvas * 3. 获取canvas的宽度、高度(稍微大一点) * 4. 将pdf的宽高设置为canvas的宽高 * 5. 将canvas转为图片 * 6. 实例化jspdf,将内容图片放在pdf中(因为内容宽高和pdf宽高一样,就只需要一页,也防止内容截断问题) */ // 得到canvas画布的单位是px 像素单位 var contentWidth = canvas.width var contentHeight = canvas.height console.log('contentWidth', contentWidth) console.log('contentHeight', contentHeight) // 将canvas转为base64图片 var pageData = canvas.toDataURL('image/jpeg', 1.0) // 设置pdf的尺寸,pdf要使用pt单位 已知 1pt/1px = 0.75 pt = (px/scale)* 0.75 // 2为上面的scale 缩放了2倍 var pdfX = (contentWidth + 10) / 2 * 0.75 var pdfY = (contentHeight + 500) / 2 * 0.75 // 500为底部留白 // 设置内容图片的尺寸,img是pt单位 var imgX = pdfX; var imgY = (contentHeight / 2 * 0.75); //内容图片这里不需要留白的距离 // 初始化jspdf 第一个参数方向:默认''时为纵向,第二个参数设置pdf内容图片使用的长度单位为pt,第三个参数为PDF的大小,单位是pt var PDF = new jsPDF('', 'pt', [pdfX, pdfY]) // 将内容图片添加到pdf中,因为内容宽高和pdf宽高一样,就只需要一页,位置就是 0,0 PDF.addImage(pageData, 'jpeg', 0, 0, imgX, imgY) PDF.save('api.pdf') })
修改实现2: 未作具体研究实现
<div className='content' id='pdfDom'> <div className='item'>内容</div> <div className='item'>内容</div> <!-- 每一块dom的class类设置成item(自定义)以此处理内容分割 --> <div className='item'>内容</div> <div className='item'>内容</div> </div> 组件内编写导出方法exportPDF,(其中isSplit方法判断是否要分割) 代码如下: import jsPDF from 'jspdf' import html2canvas from 'html2canvas' //避免分页被截断 const exportPDF = (pdfDom, title) => { const A4_WIDTH = 592.28; const A4_HEIGHT = 841.89; // myLoading 自定义等待动画组件,实现导出事件的异步等待交互 // dom的id。 let target = document.getElementById(pdfDom); let pageHeight = target.scrollWidth / A4_WIDTH * A4_HEIGHT; // 获取分割dom,此处为class类名为item的dom let lableListID = target.getElementsByClassName('item'); // let lableListID = document.getElementsByClassName('item'); // 进行分割操作,当dom内容已超出a4的高度,则将该dom前插入一个空dom,把他挤下去,分割 for (let i = 0; i < lableListID.length; i++) { let multiple = Math.ceil((lableListID[i].offsetTop + lableListID[i].offsetHeight) / pageHeight); if (isSplit(lableListID, i, multiple * pageHeight)) { let divParent = lableListID[i].parentNode; // 获取该div的父节点 let newNode = document.createElement('div'); newNode.className = 'emptyDiv'; newNode.style.background = '#01195e'; let _H = multiple * pageHeight - (lableListID[i].offsetTop + lableListID[i].offsetHeight); newNode.style.height = _H + 30 + 'px'; newNode.style.width = '100%'; let next = lableListID[i].nextSibling; // 获取div的下一个兄弟节点 // 判断兄弟节点是否存在 // console.log(next); if (next) { // 存在则将新节点插入到div的下一个兄弟节点之前,即div之后 divParent.insertBefore(newNode, next); } else { // 不存在则直接添加到最后,appendChild默认添加到divParent的最后 divParent.appendChild(newNode); } } } pdf(pdfDom, title); } // 判断是否需要添加空白div const isSplit = (nodes, index, pageHeight) => { // 计算当前这块dom是否跨越了a4大小,以此分割 if (nodes[index].offsetTop + nodes[index].offsetHeight < pageHeight && nodes[index + 1] && nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight > pageHeight) { return true; } return false; } const pdf = (pdfDom, title) => { // 避免出现浏览器滚动条导致的内容不全处理 document.body.scrollTop = document.documentElement.scrollTop = 0 //div内部滚动导致内容不全处理 // document.getElementById('app').style.height = 'auto'; setTimeout(() => { html2canvas(document.getElementById(pdfDom), { allowTaint: true, scale: 3, // 按比例增加分辨率 dpi: 300, // 分辨率 // height: document.getElementById('upload').scrollHeight, // windowHeight: document.getElementById('upload').scrollHeight }).then(canvas => { var contentWidth = canvas.width; var contentHeight = canvas.height; //一页pdf显示html页面生成的canvas高度; var pageHeight = contentWidth / 592.28 * 841.89; //未生成pdf的html页面高度 var leftHeight = contentHeight; //页面偏移 var position = 0; //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高 var imgWidth = 595.28; var imgHeight = 592.28 / contentWidth * contentHeight; var pageData = canvas.toDataURL('image/jpeg', 1.0); var pdf = new jsPDF('', 'pt', 'a4'); //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89) //当内容未超过pdf一页显示的范围,无需分页 if (leftHeight < pageHeight) { pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight); } else { while (leftHeight > 0) { pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight) leftHeight -= pageHeight; position -= 841.89; //避免添加空白页 if (leftHeight > 0) { pdf.addPage(); } } } pdf.save(`${title}.pdf`); }) }, 300) } const contentRender = () =>{ return <> // item等内容 </> } return ( <div> <Button key="exportPDF" type="primary" loading={pdfLoading} onClick={() => exportPDF('pdfDom', '文件标题')}> 导出PDF </Button> {/* 打印及预览dom */} <div className={styles.pageContainer}> <div ref={printRef} > {contentRender()} </div> </div> {/* pdf导出dom */} <div id='pdfDom' className={`${styles.pageContainer} ${styles.noDownload}`} > {contentRender()} </div> </div> ) css代码 .pageContainer { position: relative; margin: auto; padding: 48px; // 预览时候的宽度需要和打印时算上内边距后的正文宽度保持一致 // 不然会导致计算页码时出现误差 width: 700px; background-color: white; font-family: SimSun; } .noDownload { position: absolute; top: 0; z-index: -1; } 以上js代码中,'打印及预览dom'是用于打印预览的(可忽略),所以此处将 pdf下载用的dom复制了一份,设置css .noDownload 隐藏(仅用于下载pdf,不展示给用户)
特殊实现 window.print()
const printHTML = document.querySelector('#print').innerHTML window.document.body.innerHTML = printHTML window.print() // 打印完成后重新加载页面 window.location.reload()

浙公网安备 33010602011771号