泰州做兼职的网站,wordpress数据库,wordpress无法访问图片,教育类网页设计欣赏代码地址#xff1a;https://github.com/HFQ12333/export-pdf.git
html2canvas jspdf方案是前端实现页面打印的一种常用方案#xff0c;但是在实践过程中#xff0c;遇到的最大问题就是分页截断的问题#xff1a;当页面元素超过一页A4纸的时候#xff0c;连续的页面就会…代码地址https://github.com/HFQ12333/export-pdf.git
html2canvas jspdf方案是前端实现页面打印的一种常用方案但是在实践过程中遇到的最大问题就是分页截断的问题当页面元素超过一页A4纸的时候连续的页面就会因为分页而导致内容被截断进而影响了pdf的可读性。
由于网上关于分页截断的解决思路比较少所以特意将此次的解决方案记录下来。 使用 JSPDF 和 html2canvas 创建简单的 PDF文件
首先我们开始使用 JSPDF 和 html2canvas 生成一个简单的 PDF文件。
创建一个 JSPDF 实例
创建一个 JSPDF 实例设置页面的大小、方向和其他参数。参考官网可以写一个很简单的实例
var doc new jsPDF({orientation: landscape,unit: in,format: [4, 2]
}doc.text(Hello world!, 1, 1)
doc.save(two-by-four.pdf)
生成一个pdf文件并且在文件中写入一定内容其实JSPDF这个库就能做到。
但是很多业务场景下我们的目标内容会更复杂而且还要考虑样式所以最好的方式是引入html2canvas这个库将页面元素转换成base64数据然后贴在pdf中(使用addImage方法这样就能保证页面的内容。
引入了html2canvas库后我们更多关注是利用现成组件库、框架或者原生html和css实现更复杂的页面内容。
引入 html2canvas
使用 html2canvas 捕捉 HTML 内容或特定的 HTML 元素并将其转换为 Canvas。其中html2canvas 函数的主要用法是
html2canvas(element, options);
element 要渲染为 canvas 的 HTML 元素。这可以是一个 DOM 元素也可以是一个选择器字符串表示需要渲染的元素。options可选 一个包含配置选项的对象用于定制 html2canvas 的行为。
以下是一些常见的配置选项
allowTaint默认值: false 是否允许加载跨域的图片默认为 false。如果设为 truehtml2canvas 将尝试加载跨域的图片但在某些情况下可能会受到浏览器的限制。backgroundColor默认值: #ffffff canvas 的背景颜色。useCORS默认值: false 是否使用 CORSCross-Origin Resource Sharing来加载图片。如果设置为 true则 html2canvas 将尝试使用 CORS 来加载图片。logging默认值: false 是否输出日志信息到控制台。width 和 height canvas 的宽度和高度。如果未指定则默认为目标元素的宽度和高度。scale默认值: window.devicePixelRatio 缩放因子决定 canvas 的分辨率。
下面是一个简单的demo可以看到html2canvas能够将dom元素转化为一张base64图片将鼠标选中元素可以感受到图片和文字的不同。
div idcapture stylepadding: 10px; background: #f5da55h4 stylecolor: #000; Hello world!/h4
/divhtml2canvas(document.querySelector(#capture)).then(canvas {document.body.appendChild(canvas)
}); 将html2canvas转化的图片放到pdf中
这一步我们需要使用JSPDF 的addImage方法其语法如下
addImage(imageData, format, x, y, width, height, alias, compression)
imageData - 要添加的图像数据。可以是图像的 URL、图像的 base64 编码字符串或图像的二进制数据format - 图像的格式。可以是 JPEG、PNG 或 TIFF。x - 图像在 PDF 文档中的 x 坐标。y - 图像在 PDF 文档中的 y 坐标。width - 图像的宽度。height - 图像的高度。alias - 图像的别名。此别名可用于在 PDF 文档中引用图像。compression - 图像的压缩级别。可以是 NONE、FAST 或 SLOW。
下面是一串示例代码
import jsPDF from jspdf;export default function addImageUsage() {const doc new jsPDF();const imageData 【替换成base64数据流】;doc.addImage(imageData, png, 0, 0, 10, 10);doc.addImage(imageData, png, 100, 100, 10, 10);doc.addImage(imageData, png, 200, 200, 10, 10);drawNet(doc);doc.save(test.pdf);
}const drawNet (doc) {const gap 10;const start [0, 0];const end [595.28, 841.89];// 所有横线for (let i start[0]; i end[0]; i i gap) {doc.line(i, 0, i, end[0]);}// 所有纵线for (let j start[1]; j end[1]; j j gap) {doc.line(0, j, end[1], j);}
};
此示例将在 PDF 文档默认是A4纸大小宽高为[595.28, 841.89]像素的 (10, 10) 、(100, 100) 、(200, 200) 坐标处添加一张png 图像。图像的宽度和高度将分别为 10 和 10 像素为了了解pdf中的坐标系统此示例还在pdf文档中生成了间距为10px的网格系统。 JSPDF 和 html2canvas结合起来用
了解了上面的三个关键点接下来我们将这三个步骤串联起来实现一个基本的html→pdf的方案。大致步骤如下
写一个基本html页面创建jspdf实例获取页面的dom节点使用html2canvas将其转化为base64数据流将base64数据流装载到jspdf提供的addImage方法中保存pdf
基于这5个步骤可以实现基本的页面打印。
import html2canvas from html2canvas;
import jsPDF, { RGBAData } from jspdf;// 将元素转化为canvas元素
// 通过 放大 提高清晰度
// width为内容宽度
async function toCanvas(element: HTMLElement) {if (!element) return { width: 0, height: 0 };// canvas元素const canvas await html2canvas(element, {scale: window.devicePixelRatio * 2, // 增加清晰度useCORS: true // 允许跨域});// 获取canvas转化后的宽高const { width: canvasWidth, height: canvasHeight } canvas;// 转化成图片Dataconst canvasData canvas.toDataURL(image/jpeg, 1.0);return { width: canvasWidth, height: canvasHeight, data: canvasData };
}/*** 生成pdf(A4多页pdf截断问题 包括页眉、页脚 和 上下左右留空的护理)*/
export async function generatePDF({/** pdf内容的dom元素 */element,/** pdf文件名 */filename
}) {if (!(element instanceof HTMLElement)) {return;}const pdf new jsPDF();// 一页的高度 转换宽度为一页元素的宽度const {width: imageWidth,height: imageHeight,data} await toCanvas(element);// 添加图片function addImage(_x: number,_y: number,pdfInstance: jsPDF,base_data:| string| HTMLImageElement| HTMLCanvasElement| Uint8Array| RGBAData,_width: number,_height: number) {pdfInstance.addImage(base_data, JPEG, _x, _y, _width, _height);}addImage(0, 0, pdf, data!, imageWidth, imageHeight);return pdf.save(filename);
}
多页比例缩放循环移位
通常在我们的实践中会发现2个问题
生成的pdf内容与实际的页面元素比例不一致页面内容超出一页pdf的高度但是生成的pdf只有一页没有展示全部的页面信息
这两个问题的解决方案是等比例缩放循环移位
等比例缩放
通过比例缩放实现页面内容等比例展示在pdf文档中
令页面元素的宽高为x, y转化成canvas图片的宽高pdf文档的宽高为w, h。因为高度可以通过加页延伸所以可以按照宽度进行缩放缩放后的图片高度可以通过下列公式计算
y_scaled(w/x)\*yy\_{scaled} (w / x) \* yy_scaled(w/x)\*y
循环移位
如果页面的高度超出了pdf文档的高度即y h使用addPage方法添加一页即可。但是在新的一页中我们的图片内容的高度需要调整。
假设y 2 * h这意味我们需要两页才能完整得展示页面内容。在一页pdf中图片在起始位置插入即可即
PDF.addImage(pageData, JPEG, 0, 0, x, y)// 注意x,y 是缩放后的大小
在第二页pdf中图片的纵向位置需要调整一页pdf的高度即
PDF.addImage(pageData, JPEG, 0, -h, x, y)// 注意x,y 是缩放后的大小
通过循环计算剩余高度然后不停调整纵向位置移动base64的图片位置可以解决多页的问题。
分页截断的挑战
尽管 JSPDF 和 html2canvas 是功能强大的工具但是他们也有很多槽点比如得手动分页手动处理分页截断的问题。等你实践到这一步就开始面临分页截断的问题类似的问题也有网友在Github上提出但是底下依然没有很好的解决思路。
处理分页截断的原理就是在使用addImage之前将html进行分页通过维护一个高度位置数据来记录每次循环迭代addImage的位置。
从高到低遍历维护一个分页数组pages该数组记录每一页的起始位置如pages[0] 对应 第一页起始位置pages[1] 对应第二页起始位置 接下来我们重点讨论如何将页面进行切割然后生成pages这个数组。
假设页面的高度是1500pdf宽高是[500, 900]如果不用处理分页截断的问题我们可以想到第一页0-900是用来承载页面从高度为0到900的信息
第二页900-1800是用来承载页面从高度900到1500的所以pages数组为[0, 900]。
如果要处理分页截断呢这时候就需要计算页面元素的距离pdf文档起始位置的高度h1以及该元素的内部高度h2通过这两个高度来判断这个元素要不要放在下一页防止截断示意图如下 如果h1 h2 页面高度 这时候说明这个元素不处理的就会被分页截断所以应该要把这个元素放到第二页去渲染这就意味着pages记录的数据要变化示意图如下可以看到pages[1]我们往上调整了比第二页pdf的起始位置更高。 说明渲染第二页pdf的时候要从h1开始渲染pages数组为[0, h1]解释为第一页pdf渲染页面高度区域为0-900, 第二页pdf渲染html高度区域为h1-1500。注意到第一页渲染的时候到尾部的时候**会有部分内容和第二页头部内容重合。**因为h1到900这部分的内容肯定会渲染这部分内容一直都是页面元素我们改变pages[1]的值的原因只是创建一个副本让页面看起来内容没有被截断。
为了解决这个问题为了美观我们用填充一块白色区域遮掉它此处使用jspdf的rect和setFillColor方法把重合的区域遮白处理。
pdf.setFillColor(255, 255, 255);
pdf.rect(x, y, Math.ceil(_width), Math.ceil(_height), F);
如何获得h1和h2
上面我们谈到了h1和h2其中h1是元素盒子的上边距到打印区域的高度比例缩放后的高度h2是元素盒子的内部高度。
计算h1: getBoundingClientRect方法
const rect contentElement.getBoundingClientRect() || {};
const topDistance rect.top;
return topDistance; 计算h2 offsetHeight方法 值得注意的是因为打印区域的html元素不一定是从窗口顶部开始所以为了计算实际的h1(元素到打印区域的顶部距离可以采用这样的方法 ●用getBoundingClientRect方法计算元素到窗口顶部的距离 ●循环打印之前将pages信息针对第一个元素进行一个高度校准。
/ 对pages进行一个值的修正因为pages生成是根据根元素来的根元素并不是我们实际要打印的元素而是element
// 所以要把它修正让其值是以真实的打印元素顶部节点为准
const newPages pages.map((item) item - pages[0]); 文章转载自: http://www.morning.kqpxb.cn.gov.cn.kqpxb.cn http://www.morning.drhnj.cn.gov.cn.drhnj.cn http://www.morning.jrplk.cn.gov.cn.jrplk.cn http://www.morning.qineryuyin.com.gov.cn.qineryuyin.com http://www.morning.rswfj.cn.gov.cn.rswfj.cn http://www.morning.jbkcs.cn.gov.cn.jbkcs.cn http://www.morning.ldhbs.cn.gov.cn.ldhbs.cn http://www.morning.qggcc.cn.gov.cn.qggcc.cn http://www.morning.ndmbz.cn.gov.cn.ndmbz.cn http://www.morning.pqnpd.cn.gov.cn.pqnpd.cn http://www.morning.lcplz.cn.gov.cn.lcplz.cn http://www.morning.nmymn.cn.gov.cn.nmymn.cn http://www.morning.zrmxp.cn.gov.cn.zrmxp.cn http://www.morning.hmbxd.cn.gov.cn.hmbxd.cn http://www.morning.xrlwr.cn.gov.cn.xrlwr.cn http://www.morning.pngfx.cn.gov.cn.pngfx.cn http://www.morning.wglhz.cn.gov.cn.wglhz.cn http://www.morning.lcxzg.cn.gov.cn.lcxzg.cn http://www.morning.lxctl.cn.gov.cn.lxctl.cn http://www.morning.qkbwd.cn.gov.cn.qkbwd.cn http://www.morning.lhyhx.cn.gov.cn.lhyhx.cn http://www.morning.gjcdr.cn.gov.cn.gjcdr.cn http://www.morning.tsdjj.cn.gov.cn.tsdjj.cn http://www.morning.rqzyz.cn.gov.cn.rqzyz.cn http://www.morning.ywpwg.cn.gov.cn.ywpwg.cn http://www.morning.kspfq.cn.gov.cn.kspfq.cn http://www.morning.bpmdz.cn.gov.cn.bpmdz.cn http://www.morning.hzryl.cn.gov.cn.hzryl.cn http://www.morning.mtgnd.cn.gov.cn.mtgnd.cn http://www.morning.bzfwn.cn.gov.cn.bzfwn.cn http://www.morning.qwpdl.cn.gov.cn.qwpdl.cn http://www.morning.zlwg.cn.gov.cn.zlwg.cn http://www.morning.zcyxq.cn.gov.cn.zcyxq.cn http://www.morning.ysqb.cn.gov.cn.ysqb.cn http://www.morning.rmpkn.cn.gov.cn.rmpkn.cn http://www.morning.bojkosvit.com.gov.cn.bojkosvit.com http://www.morning.jppb.cn.gov.cn.jppb.cn http://www.morning.ssmhn.cn.gov.cn.ssmhn.cn http://www.morning.cryb.cn.gov.cn.cryb.cn http://www.morning.ffptd.cn.gov.cn.ffptd.cn http://www.morning.gynlc.cn.gov.cn.gynlc.cn http://www.morning.kgnrh.cn.gov.cn.kgnrh.cn http://www.morning.yybcx.cn.gov.cn.yybcx.cn http://www.morning.rdlong.com.gov.cn.rdlong.com http://www.morning.rqgbd.cn.gov.cn.rqgbd.cn http://www.morning.fhghy.cn.gov.cn.fhghy.cn http://www.morning.nfcxq.cn.gov.cn.nfcxq.cn http://www.morning.rnxw.cn.gov.cn.rnxw.cn http://www.morning.slwfy.cn.gov.cn.slwfy.cn http://www.morning.qxwwg.cn.gov.cn.qxwwg.cn http://www.morning.kaweilu.com.gov.cn.kaweilu.com http://www.morning.lbgsh.cn.gov.cn.lbgsh.cn http://www.morning.rmpkn.cn.gov.cn.rmpkn.cn http://www.morning.dnphd.cn.gov.cn.dnphd.cn http://www.morning.wbyqy.cn.gov.cn.wbyqy.cn http://www.morning.nyqm.cn.gov.cn.nyqm.cn http://www.morning.mtgkq.cn.gov.cn.mtgkq.cn http://www.morning.zlfxp.cn.gov.cn.zlfxp.cn http://www.morning.mdnnz.cn.gov.cn.mdnnz.cn http://www.morning.zmyzt.cn.gov.cn.zmyzt.cn http://www.morning.xdpjf.cn.gov.cn.xdpjf.cn http://www.morning.dglszn.com.gov.cn.dglszn.com http://www.morning.lyrgp.cn.gov.cn.lyrgp.cn http://www.morning.rycbz.cn.gov.cn.rycbz.cn http://www.morning.txqsm.cn.gov.cn.txqsm.cn http://www.morning.kwqqs.cn.gov.cn.kwqqs.cn http://www.morning.rykgh.cn.gov.cn.rykgh.cn http://www.morning.mspqw.cn.gov.cn.mspqw.cn http://www.morning.srbmc.cn.gov.cn.srbmc.cn http://www.morning.jfjbl.cn.gov.cn.jfjbl.cn http://www.morning.ktxd.cn.gov.cn.ktxd.cn http://www.morning.jtsdk.cn.gov.cn.jtsdk.cn http://www.morning.mnyzz.cn.gov.cn.mnyzz.cn http://www.morning.cfccp.cn.gov.cn.cfccp.cn http://www.morning.dktyc.cn.gov.cn.dktyc.cn http://www.morning.sjwzz.cn.gov.cn.sjwzz.cn http://www.morning.ktmpw.cn.gov.cn.ktmpw.cn http://www.morning.trplf.cn.gov.cn.trplf.cn http://www.morning.zxzgr.cn.gov.cn.zxzgr.cn http://www.morning.sbrrf.cn.gov.cn.sbrrf.cn