实现前端页面局部转 pdf 及 打印 加分页防止内容截断 您所在的位置:网站首页 网页转pdf如何完整打印图片 实现前端页面局部转 pdf 及 打印 加分页防止内容截断

实现前端页面局部转 pdf 及 打印 加分页防止内容截断

2024-07-11 22:39| 来源: 网络整理| 查看: 265

再次强调实践出真知,新项目迭代涉及到一个管理报告的下载及打印,但是项目中以往的这种功能实现主要核心在后端,如pdf 的生成,打印也是有现成的文件地址等,但这次的报告中内容比较复杂,有表格,有几个echars 数据,以及长篇的描述,后端表示这个由后端生成pdf 不太现实,因此主要任务就留在了前端。

核心库 html2Canvas  jspdf print-js 实现思路

1、html2Canvas  可以将特定容器标签的内容转换为图片,通过特定API 转换为对应的base64 格式的数据

2、jspdf 库  调用核心API addImage() 及 save() 方法可以将base64 的数据转换为pdf 保存到本地

3、print-js 打印的核心库,直接传入数据实现打印,不需要再重新刷新页面

重点思考 !!!分页内容防截断

由于要转pdf 和 打印 的管理报告不是一页范围内的,因此需要考虑分页,关于分页转pdf 有很多分享,可是忽略了一点,分页的时候一定不能把有些内容给截断 ,比如一个表格,一个图片,或者报告中的echars 图标等,怎么办?刚开始一点思路没有后,后来简书上看了一篇文章打开了思路。 https://www.jianshu.com/p/9f6ebc0e0d70 ,但最后没有采用,因为这个思路还是有点绕,而且需要基本所有内容标签都加上对应防截断tag,其实是没必要的。

解决思路!!!!

使用html2Canvas  +  jspdf 实现前端页面转pdf ,改变pdf 分页格式的唯一思路是 先改变转 pdf 的 dom (因为我在没有了解清楚的时候也在,dom 转换后pdf 分页的时候动过心思,不成功因为一切都是基于一个完整的base64 格式的 image 数据)

将确保不被分割的dom 元素 加上特定的tag 标签,判断此dom 元素的最上面和最下面是否在同一页中,如果不在说名不处理就会被截断,怎么处理,不能被截断的元素上方插入对应的空白快占位,已达到将当前元素放到下一页的目的(当前页面高度 - dom元素最上方位置 = 需要插入空白块的高度)

 

关于局部分页打印

正常将dom 元素按照A4 纸的标准进行分页后,dom 转pdf 的数据在打印时可以自动分页,万万没想到,预览状态下打印的一页内容,比设计的一页内容多,导致打印的时候元素又被截断,分析的原因是电脑里A4纸的标准和我设定的不一样,我设定的高度不够,因此试着调试了一下高度,解决了,还有待多个电脑测试。

核心代码

思路很早就明确了,我认为这种方法一定可以成功,万万没想到,写错了一个数据,导致忙活了一个周,当然这一个周也开发了别的功能,当我动不动就会调试一下下载 打印,因为这块经理也不确定前端能不能做好,所以就放得比较宽,想知道529 和 592 之间的差距有多远吗,就是我一周的时间和几乎怀疑自己的焦虑,因为我认为思路完全没问题的,知道今天其他功能完成我准备好好顺顺代码,结果就是一个数字写的问题。

convertPdf(isPrint) { let title = "你想要的保存pdf文件的名字" // 如果这个页面有左右移动,canvas 也要做响应的移动,不然会出现canvas 内容不全 const xOffset = window.pageXOffset // 避免笔下误 灯下黑 统一写 const A4_WIDTH = 592.28 // const A4_HEIGHT = 841.89 const A4_HEIGHT = 880 let printDom = document.querySelector('#printBox') // 根据A4的宽高计算DOM页面一页应该对应的高度 let pageHeight = printDom.offsetWidth / A4_WIDTH * A4_HEIGHT // 将所有不允许被截断的元素进行处理 let wholeNodes = document.querySelectorAll('.whole-node') for (let i = 0; i < wholeNodes.length; i++) { //1、 判断当前的不可分页元素是否在两页显示 const topPageNum = Math.ceil((wholeNodes[i].offsetTop) / pageHeight) const bottomPageNum = Math.ceil((wholeNodes[i].offsetTop + wholeNodes[i] + offsetHeight) / pageHeight) if (topPageNum !== bottomPageNum) { //说明该dom会被截断 // 2、插入空白块使被截断元素下移 let divParent = wholeNodes[i].parentNode let newBlock = document.createElement('div') newBlock.className = 'emptyDiv' newBlock.style.background = '#fff' // 3、计算插入空白块的高度 可以适当流出空间使得内容太靠边,根据自己需求而定 let _H = topPageNum * pageHeight - wholeNodes[i].offsetTop newBlock.style.height = _H + 30 + 'px' divParent.insertBefore(newBlock, wholeNodes[i]) } // 以上完成dom层面的分页 可以转为图片进一步处理了 html2Canvas(printDom, { height: printDom.offsetHeight, width: printDom.offsetWidth, scrollX: -xOffset, allowTaint: true }).then(canvas => { //dom 已经转换为canvas 对象,可以将插入的空白块删除了 let emptyDivs = document.querySelectorAll('.emptyDiv') for (let i = 0; i < emptyDivs.length; i++) { emptyDivs[i].parentNode.removeChild(emptyDivs[i]) } // 有一点重复的代码 let contentWidth = canvas.width let contentHeight = canvas.height let pageHeight = contentWidth / A4_WIDTH * A4_HEIGHT let leftHeight = contentHeight let position = 0 let imgWidth = A4_WIDTH let imgHeight = A4_WIDTH / contentWidth * contentHeight let pageData = canvas.toDataURL('image/jpeg', 1.0) if (isPrint) { //如果是打印,可以拿着分号页的数据 直接使用 printJs({ printable: pageData, type: 'image', base64: true, documentTitle: '\u200E' }) return } //计算分页的pdf let PDF = new JsPDF('', 'pt', 'a4') if (leftHeight 0) { PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight) leftHeight -= pageHeight position -= A4_HEIGHT if (leftHeight > 0) { PDF.addPage() } } } PDF.save(title + '.pdf') }) } },

dom 元素要做的处理就是添加对应的class 标记就行了。

 

如果有更好的建议,欢迎我们一起讨论 解决,比如打印的时候动态分页,有没有更优办法。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有