0


前端将html导出pdf文件解决分页问题

文章目录

  • 这是借鉴了qq_251025116大佬的解决方案并优化升级完成的,原文链接

1.安装依赖

    npm install jspdf html2canvas

2.使用方法

import htmlToPdffrom './index.js'constsuc=()=>{
      message.success('success');};//记得在需要打印的div上面添加 idlet dom = document.querySelector('#testPdf');let pdf =newhtmlToPdf(dom,'测试','splitPages',',', suc,2);
  pdf.outPutPdfFn('测试');

3.使用说明

//splitPages 是需要添加的类名,需要再那个地方分页就在那个地方添加类名 splitPages//如:<SpeciesIdentification class="splitPages":baseData="baseData"/><SpeciesIdentificationSecond class="splitPages":baseData="baseData"/><RepetPic class="splitPages":baseData="baseData"/><RepetTable class="splitPages":baseData="baseData"/><GeneralAnnotation class="splitPages":baseData="baseData"/>

导出效果对比:

截断

在这里插入图片描述

自动分页

在这里插入图片描述

具体代码 :

import jsPDF from"jspdf";import html2canvas from"html2canvas";/*
* 使用说明
* ele:需要导出pdf的容器元素(dom节点 不是id)
* pdfFileName: 导出文件的名字 通过调用outPutPdfFn方法也可传参数改变
* splitClassName: 避免分段截断的类名 当pdf有多页时需要传入此参数 , 避免pdf分页时截断元素  如表格<tr class="itemClass"></tr>
* breakClassName:自定义分页符类名,默认为break_page,添加改类名的标签被自动分页到下一页
* sucCallback:成功回调函数
* scale:增强图片清晰度 数字也打越清晰
* 调用方式 先 let pdf = new htmlToPdf(ele, 'pdf' ,'itemClass');
* 若想改变pdf名称 pdf.outPutPdfFn(fileName);  outPutPdfFn方法返回一个promise 可以使用then方法处理pdf生成后的逻辑
* */classhtmlToPdf{constructor(ele, pdfFileName, splitClassName ="itemClass", breakClassName ="break_page",sucCallback=()=>{}, scale =2){this.ele = ele;this.pdfFileName = pdfFileName;this.splitClassName = splitClassName;this.breakClassName = breakClassName;this.sucCallback = sucCallback;this.scale = scale;this.A4_WIDTH=595;this.A4_HEIGHT=842;this.pageHeight =0this.pageNum =1};asyncgetPDF(resolve){let ele =this.ele;let pdfFileName =this.pdfFileName
        let eleW = ele.offsetWidth // 获得该容器的宽let eleH = ele.scrollHeight // 获得该容器的高let eleOffsetTop = ele.offsetTop // 获得该容器到文档顶部的距离let eleOffsetLeft = ele.offsetLeft // 获得该容器到文档最左的距离let canvas = document.createElement("canvas")let abs =0let win_in = document.documentElement.clientWidth || document.body.clientWidth // 获得当前可视窗口的宽度(不包含滚动条)let win_out = window.innerWidth // 获得当前窗口的宽度(包含滚动条)if(win_out > win_in){
            abs =(win_out - win_in)/2// 获得滚动条宽度的一半} canvas.width = eleW *2// 将画布宽&&高放大两倍
        canvas.height = eleH *2let context = canvas.getContext("2d")
        context.scale(this.scale,this.scale)// 增强图片清晰度
        context.translate(- eleOffsetLeft - abs,- eleOffsetTop)html2canvas(ele,{useCORS:true// 允许canvas画布内可以跨域请求外部链接图片, 允许跨域请求。}).then(asynccanvas=>{let contentWidth = canvas.width
            let contentHeight = canvas.height
            // 一页pdf显示html页面生成的canvas高度;this.pageHeight =(contentWidth /this.A4_WIDTH)*this.A4_HEIGHT// 这样写的目的在于保持宽高比例一致 this.pageHeight/canvas.width = a4纸高度/a4纸宽度// 宽度和canvas.width保持一致// 未生成pdf的html页面高度let leftHeight = contentHeight
            // 页面偏移let position =0// a4纸的尺寸[595,842],单位像素,html页面生成的canvas在pdf中图片的宽高let imgWidth =this.A4_WIDTH-10// -10为了页面有右边距let imgHeight =(this.A4_WIDTH/ contentWidth)* contentHeight
            let pageData = canvas.toDataURL("image/jpeg",1.0)let pdf =jsPDF("","pt","a4");// 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)// 当内容未超过pdf一页显示的范围,无需分页if(leftHeight <this.pageHeight){// 在pdf.addImage(pageData, 'JPEG', 左,上,宽度,高度)设置在pdf中显示;// pdf.addImage(pageData, "JPEG", 5, 0, imgWidth, imgHeight)
                pdf.addImage(pageData,'JPEG',6,40, imgWidth -12, imgHeight -80);}else{// 分页while(leftHeight >0){
                    pdf.addImage(pageData,"JPEG",6, position +40, imgWidth -12, imgHeight -80)
                    leftHeight -=this.pageHeight
                    position -=this.A4_HEIGHT// 避免添加空白页if(leftHeight >0){
                        pdf.addPage()}}} pdf.save(pdfFileName +".pdf",{returnPromise:true}).then(()=>{// 去除添加的空div 防止页面混乱let doms = document.querySelectorAll('.emptyDiv')for(let i =0; i < doms.length; i++){
                    doms[i].remove();}});this.ele.style.height ='';this.sucCallback()resolve();})};// 输出pdfasyncoutPutPdfFn(pdfFileName){returnnewPromise((resolve, reject)=>{// 进行分割操作,当dom内容已超出a4的高度,则将该dom前插入一个空dom,把他挤下去,分割let target =this.ele;this.pageHeight = target.scrollWidth /this.A4_WIDTH*this.A4_HEIGHT;this.ele.style.height ='initial';
            pdfFileName ?this.pdfFileName = pdfFileName :null;this.pageNum =1;// pdf页数this.domEach(this.ele)// 异步函数,导出成功后处理交互this.getPDF(resolve, reject);})};domEach(dom){let childNodes = dom.childNodes
        childNodes.forEach((childDom, index)=>{if(this.hasClass(childDom,this.splitClassName)){let node = childDom;let eleBounding =this.ele.getBoundingClientRect();let bound = node.getBoundingClientRect();let offset2Ele = bound.top - eleBounding.top
                let currentPage = Math.ceil((bound.bottom - eleBounding.top)/this.pageHeight);// 当前元素应该在哪一页if(this.pageNum < currentPage){this.pageNum++let divParent = childDom.parentNode;// 获取该div的父节点let newNode = document.createElement('div');
                    newNode.className ='emptyDiv';
                    newNode.style.background ='white';
                    newNode.style.height =(this.pageHeight *(this.pageNum -1)- offset2Ele +30)+'px';// +30为了在换下一页时有顶部的边距
                    newNode.style.width ='100%';let next = childDom.nextSibling;// 获取div的下一个兄弟节点// 判断兄弟节点是否存在if(next){// 存在则将新节点插入到div的下一个兄弟节点之前,即div之后
                        divParent.insertBefore(newNode, node);}else{// 不存在则直接添加到最后,appendChild默认添加到divParent的最后
                        divParent.appendChild(newNode);}}}if(this.hasClass(childDom,this.breakClassName)){this.pageNum++
                console.log('break_page');let eleBounding =this.ele.getBoundingClientRect();let bound = childDom.getBoundingClientRect();let offset2Ele = bound.top - eleBounding.top
                // 剩余高度let alreadyHeight = offset2Ele %this.pageHeight
                let remainingHeight =this.pageHeight - alreadyHeight +20
                childDom.style.height = remainingHeight +'px'}if(childDom.childNodes.length){this.domEach(childDom)}})}hasClass(element, cls){return(``+ element.className +``).indexOf(``+ cls +``)>-1;}}exportdefault htmlToPdf;
标签: 前端 html pdf

本文转载自: https://blog.csdn.net/qq_43940789/article/details/136498998
版权归原作者 夜空孤狼啸 所有, 如有侵权,请联系我们删除。

“前端将html导出pdf文件解决分页问题”的评论:

还没有评论