1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 利用 html2canvas 和 jspdf 导出 echarts ( html页面 )为pdf

利用 html2canvas 和 jspdf 导出 echarts ( html页面 )为pdf

时间:2021-03-21 11:06:11

相关推荐

利用 html2canvas 和 jspdf 导出 echarts ( html页面 )为pdf

前言:这段时间在项目开发中,遇到这样一个需求:前端在一个页面中使用echarts生成了几个图表,需要可以将他们导出为一个pdf。虽然echarts自身有下载,但只能单个图表下载为图片,所以不满需求。

根据调研,决定采用html2canvas 和 jspdf 的方式实现,即使用html2canvas 将页面转成图片后,放到pdf中导出。

一、安装插件与引入

html2canvas:npm install html2canvas --save-dev

import html2canvas from 'html2canvas';

jspdf:npminstalljspdf--save-dev

import jsPDF from 'jspdf';

二、核心js (mainBox 为要导出的盒子id

html2canvas(document.getElementById('mainBox'),{dpi: 200,//导出pdf清晰度useCORS: true // 【重要】开启跨域配置}).then(function(canvas) {// document.body.appendChild(canvas);let contentWidth = canvas.width;let contentHeight = canvas.height;//一页pdf显示html页面生成的canvas高度;let pageHeight = contentWidth / 592.28 * 841.89;//未生成pdf的html页面高度let leftHeight = contentHeight;//pdf页面偏移let position = 0;//html页面生成的canvas在pdf中图片的宽高(a4纸的尺寸[595.28,841.89])let imgWidth = 595.28;let imgHeight = 592.28 / contentWidth * contentHeight;let pageData = canvas.toDataURL('image/jpeg', 1);let 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('TestReport.pdf');});

三、我踩过的坑

1.html2canvas 截图只能接到当前屏幕的,滚动到屏幕以外的截取不到?

解决方法:请注意如果内容高度超过了屏幕高度,请确认是否有滚动条,我就是因为项目对滚动条做了特殊处理,不会显示出来,滚动是自己封装实现的,导致了截图不全的问题。

还有一种情况,我将下载按钮放在要导出的盒子下方,会导致截图不全,但我将按钮放在盒子上方就可以,没找到原因....

html2canvas 和 jspdf 这个方法网上有很多现实文章,可自行搜索参考。特别是html2canvas 的用法,有坑,使用时请注意

续集:

使用场景:导出页面,页面中有大量图片,文字以及附件的展示(附件内容不管) =》 类似一张试卷

遇到的问题:

1. 截图后图片不显示 => 原因:在html2canvas里面,是使用脚本去操作的,也就是说使用脚本把html转换成canvas,但是有一个限制,那就是不能使用跨源的图片。而 img 标签本身可以避免跨域问题,所以显示没有问题。

后期处理跨域即可

2. 多行输入框 textarea 截图后内容不换行

将textarea 换成普通div即可,并按 textarea 完善样式

3. 内容被断行

这个需要计算一张纸能显示多少内容并且换页即可

处理换页完整逻辑:

// --------------------------- 方法一 --------------------------- // 导出内容handleExport() {this.exportLoading = true;// 定义A4 纸的宽高const A4_WIDTH = 595.28;const A4_HEIGHT = 841.89;this.$nextTick(() => {// 获取到截图domconst target = this.$refs.mainBox;// 以A4纸的大小去计算出 一页pdf能显示高 => 向上取整 (两种方式计算的结果是一样的,下面的更好记录 页面宽/页面高 = A4宽 / A4 高)// let pageHeight = Math.ceil(target.scrollWidth / A4_WIDTH * A4_HEIGHT);let pageHeight = Math.ceil(target.scrollWidth / (A4_WIDTH / A4_HEIGHT));// 获取分割dom,此处为class类名为question-item的domlet lableListID = target.getElementsByClassName('print-item');// 进行分割操作,当dom内容已超出a4的高度,则将该dom前插入一个空dom,把他挤下去,分割for (let i = 0; i < lableListID.length; i++) {/** offsetTop 是当前元素距离弹窗顶部的距离 => 这个偏移量是内容到dialog顶部(包含了dialog header);* offsetHeight 是当前元素本身的高度,包含内边距(padding)和边框(border)* 当前元素高度+距离顶部的偏移量 / 一页显示的高度 取整 => 得到的是该dom应该放在第几页*/ let multiple = Math.ceil((lableListID[i].offsetTop + lableListID[i].offsetHeight) / pageHeight);if (this.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);// 插入元素的高度 = pdf这一页剩余空间 + 65(dialog header的高度,需要减去) + 50 (保证下一页顶部有一点padding)newNode.style.height = _H + 65 + 50 + 'px';newNode.style.width = '100%';let next = lableListID[i].nextSibling; // 获取div的下一个兄弟节点// 判断兄弟节点是否存在if (next) {// 存在则将新节点插入到div的下一个兄弟节点之前,即div之后divParent.insertBefore(newNode, next);} else {// 不存在则直接添加到最后,appendChild默认添加到divParent的最后divParent.appendChild(newNode);}}}this.pdf();});},// --------------------------- 方法二 --------------------------- // 判断是否需要添加空白divisSplit (nodes, index, pageHeight) {// 计算当前这块dom是否跨越了a4大小,以此分割 => 当前这个dom在前一页(小于一页显示高度pageHeight),但下一个dom在下一页了(大于一页显示高度pageHeight)if (nodes[index].offsetTop + nodes[index].offsetHeight < pageHeight && nodes[index + 1] && nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight > pageHeight) {return true;}return false;},// --------------------------- 方法三 --------------------------- pdf() {const JsPDF = jsPDF;setTimeout(() => {html2canvas(this.$refs.mainBox, {dpi: 200, //导出pdf清晰度useCORS: true // 【重要】开启跨域配置}).then(canvas => {// document.body.appendChild(canvas);let contentWidth = canvas.width;let contentHeight = canvas.height;//一页pdf显示html页面生成的canvas高度;let pageHeight = contentWidth / 595.28 * 841.89;//未生成pdf的html页面高度let leftHeight = contentHeight;//pdf页面偏移let position = 0;//html页面生成的canvas在pdf中图片的宽高(a4纸的尺寸[595.28,841.89])let imgWidth = 595.28;let imgHeight = 595.28 / contentWidth * contentHeight;let pageData = canvas.toDataURL('image/jpeg', 1);let 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(`TestReport.pdf`);this.exportLoading = true;this.dialogVisible = false;});}, 300)},

官方文档:html2canvas:Getting Started | html2canvas

jspdf:jspdf - npm

参考博客:/p/651c40d565e4

文章仅为本人学习过程的一个记录,仅供参考,如有问题,欢迎指出

对博客文章的参考,若原文章博主介意,请联系删除!请原谅

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。