纯前端--原生js将html页面变成pdf文件(html2canvas+jsPDF)

ᥬ 小月亮 2024-07-31 17:03:01 阅读 96

一、html2canvas – 将dom变成图片:

下载或者安装html2canvas:官网

1、将文档放在本地,用原生js进行引用和使用。

① 新建一个名为 <code>html2canvas.min.js 的文件,并且将线上的内容进行复制。

② 引入 js 文件:

// js直接引入 -- 未尝试

<script type="text/javascript" src="XXX/html2canvas.js"></script>code>

// layui使用

// 首先在html2canvas.js文件中添加exports

layui.define([],function(exports){

// 复制的内容...

exports('html2canvas',html2canvas);

})

// 其次进行自定义插件的引入

layui.define(['appsmenu'],function (exports) {

exports("conf", {

// 第三方扩展

extend: {

// 引入html转图片的插件

html2canvas: "lay/extends/html2canvas.min",

}

}

})

2、使用 npm 进行安装使用:

待续。。。

二、jsPDF – 将图片变成pdf

下载或者安装jsPDF :

github中文网站CDN

Jspdf.es.js:ES 2015 模块格式。Jspdf.umd.js:UMD模块格式,用于 AMD 或脚本标签加载。Jspdf.polyfills.js:Internet Explorer等旧浏览器所需的兼容文件。

1、将文档放在本地,用原生js进行引用和使用。

① 新建一个名为 jsPDF.min.js 的文件,并且将线上(我找到的都不能用)或者资源 的内容进行复制。

② 引入 js 文件:

// js直接引入 -- 未尝试

<script type="text/javascript" src="XXX/jsPDF.js"></script>code>

// CDN引入 -- 未尝试

<script type="text/javascript" src="https://cdn.staticfile.org/jspdf/2.5.1/jspdf.umd.min.js"></script>code>

// layui使用

// 首先在jsPDF.min.js文件中添加exports

layui.define([],function(exports){

exports('jsPDF',jsPDF);

})

// 其次进行自定义插件的引入

layui.define(['appsmenu'],function (exports) {

exports("conf", {

// 第三方扩展

extend: {

// 引入图片转pdf的插件

jsPDF: "lay/extends/jsPDF.min",

}

}

})

2、使用 npm 进行安装使用:

待续。。。

三、普通使用(html2canvas+jsPDF):

1、 layui 或者原生js使用:

// html:

<div id="box">code>

<button id="btn">下载为pdf</button>code>

内容....

</div>

// js:

// layui引入:

layui.define(['html2canvas', 'jsPDF'], function (exports) {

var html2canvas = layui.html2canvas; // 引入html转图片

var jsPDF = layui.jsPDF; // 引入图片转pdf

// 初始化

var init = function() {

// 点击下载按钮

document.getElementById("btn").onclick=function(){

html2canvas(document.getElementById("box"),{

allowTaint: false, // 是否允许跨域图像。会污染画布,导致无法使用canvas.toDataURL 方法

backgroundColor: '#fff', // 画布背景色(如果未在DOM中指定)。设置null为透明

useCORS: true, // 是否尝试使用CORS从服务器加载图像

dpi: 192, // 导出pdf清晰度

scale: window.devicePixelRatio * 3, // 用于渲染的比例。默认为浏览器设备像素比率。

}).then(canvas => {

// html生成图片的数据

var imageData = canvas.toDataURL('image/jpeg', 1.0);

// 原本的html页面的宽高

const canvasWidth = canvas.width;

const canvasHeight = canvas.height;

// 当分辨率是72像素/英寸时,A4纸像素长宽分别是842×595

var a4Width = 595; // A4 宽度

var a4Height = (595 / canvasWidth) * canvasHeight; // A4总高度

// 生成pdf的一页显示html的高度

let pageHeight = canvasWidth / 595 * 842;

// 未生成pdf的html页面高度,最初是整体的高度

let restHeight = canvasHeight;

// 页面上下偏移的大小

var position = 0;

/**

* 参数1:方向:l:横向 p:纵向

* 参数2:单位:"pt"、"mm"、"cm"、"m"、"in"、"px"

* 参数3:格式:默认为a4

*/

var pdf = new jsPDF('p', 'pt', 'a4');

// 当内容未超过pdf一页显示的范围,无需分页

if (restHeight < pageHeight) {

/**

* 将图像添加到PDF中

* 参数1:图片的url

* 参数2:图片的格式

* 参数3:图片上下偏移的大小

* 参数4:原始宽度

* 参数5:原始高度

*/

pdf.addImage(imageData, 'JPEG', 0, position, a4Width, a4Height );

} else {

while(restHeight > 0) {

pdf.addImage(imageData, 'JPEG',0, position, a4Width, a4Height)

restHeight -= pageHeight;

position -= 842;

if(restHeight > 0) {

// 在PDF文档中添加新页面

pdf.addPage();

}

}

}

// 保存为pdf格式的文件

pdf.save('生成的pdf文件.pdf')

})

}

}

var Class = {

init: function (options) {

init();

return this;

}

}

exports('XXX', Class);

)}

2、 vue/react 框架进行使用:

待续。。。

四、模块分割(html2canvas+jsPDF – 文字会截断,除了让后端做,没找到别的解决办法,感觉后端的插件比前端的更好用…):

参考链接:https://blog.csdn.net/qq_32244819/article/details/109678481

具体代码:

// 点击下载按钮

document.getElementById("btn").onclick=function(){

outPutPdfFn()

}

// 导出方法

var outPutPdfFn = function() {

const A4_WIDTH = 592.28; // A4纸的宽

const A4_HEIGHT = 841.89; // A4纸的高

console.log('正在导出pdf,请稍候...');

let target = document.getElementById('box'); // 需要打印的页面的dom

let pageHeight = target.scrollWidth / A4_WIDTH * A4_HEIGHT; // 根据比例换算一页的高度

// 获取分割的dom,即class类名为splitItem的dom

let splitItemAll = document.getElementsByClassName('splitItem');

// 进行分割操作,当分块的内容超出a4纸的高度,则在这个块之前插入一个空白的块,将原有的块下移进行分割

for (let i = 0; i < splitItemAll.length; i++) {

// 计算当前模块需要分成几部分

let modulesNum = Math.ceil((splitItemAll[i].offsetTop + splitItemAll[i].offsetHeight) / pageHeight);

if (isSplit(splitItemAll, i, modulesNum * pageHeight)) {

let divParent = splitItemAll[i].parentNode; // 获取当前需要分割块的父节点

let newNode = document.createElement('div');

newNode.className = 'emptyDiv';

newNode.style.background = '#ffffff';

// 计算需要插入块的高度

let _H = modulesNum * pageHeight - (splitItemAll[i].offsetTop + splitItemAll[i].offsetHeight);

newNode.style.height = _H + 'px';

newNode.style.width = '100%';

let nextDom = splitItemAll[i].nextSibling; // 获取当前需要分割块的下一个兄弟节点

// 判断兄弟节点是否存在

console.log(nextDom);

if (nextDom) {

// 存在则将新节点插入到下一个兄弟节点的前面

divParent.insertBefore(newNode, nextDom);

} else {

// 不存在则直接添加

divParent.appendChild(newNode);

}

}

}

getPdf('导出pdf', 'box')

}

/**

* 计算当前内容是否跨越了a4大小,以此分割

* @params nodes 拿到的所有需要分割的dom

* @params index 当前需要分割内容的索引

* @params pageHeight A4纸的高度

*/

var isSplit = function(nodes, index, pageHeight) {

// 当前需要分割的内容:内容高度+内容距离页面定位父元素(/body)的高度 < 页面的高度

// 当前需要分割的内容的下一个兄弟节点:内容高度+内容距离页面定位父元素(/body)的高度 > 页面的高度

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

var getPdf = function(title, dom) {

html2canvas(document.getElementById(dom),{

allowTaint: false, // 是否允许跨域图像。会污染画布,导致无法使用canvas.toDataURL 方法

backgroundColor: '#fff', // 画布背景色(如果未在DOM中指定)。设置null为透明

useCORS: true, // 是否尝试使用CORS从服务器加载图像

dpi: 192, // 导出pdf清晰度

scale: window.devicePixelRatio * 3 // 用于渲染的比例。默认为浏览器设备像素比率。增加清晰度

}).then(canvas => {

// html生成图片的数据

var imageData = canvas.toDataURL('image/jpeg', 1.0);

// 原本的html页面的宽高

const canvasWidth = canvas.width;

const canvasHeight = canvas.height;

// 当分辨率是72像素/英寸时,A4纸像素长宽分别是842×595

var a4Width = 592.28; // A4 宽度

var a4Height = (592.28 / canvasWidth) * canvasHeight; // A4总高度

// 生成pdf的一页显示html的高度

let pageHeight = canvasWidth / 592.28 * 841.89;

// 未生成pdf的html页面高度,最初是整体的高度

let restHeight = canvasHeight;

// 页面上下偏移的大小

var position = 0;

/**

* 参数1:方向:l:横向 p:纵向

* 参数2:单位:"pt"、"mm"、"cm"、"m"、"in"、"px"

* 参数3:格式:默认为a4

*/

var pdf = new jsPDF('p', 'pt', 'a4');

// 当内容未超过pdf一页显示的范围,无需分页

if (restHeight < pageHeight) {

/**

* 将图像添加到PDF中

* 参数1:图片的url

* 参数2:图片的格式

* 参数3:图片上下偏移的大小

* 参数4:原始宽度

* 参数5:原始高度

*/

pdf.addImage(imageData, 'JPEG', 0, 0, position, a4Height );

} else {

while(restHeight > 0) {

pdf.addImage(imageData, 'JPEG',0, position, a4Width, a4Height)

restHeight -= pageHeight;

position -= 841.89;

if(restHeight > 0) {

// 在PDF文档中添加新页面

pdf.addPage();

}

}

}

// 保存为pdf格式的文件

pdf.save(`${ title}.pdf`)

})

}

五、echarts图表模糊的解决办法:

// 方法一:初始化echarts的时候,添加清晰度配置 devicePixelRatio

echarts.init(chartDom, null, { devicePixelRatio: window.devicePixelRatio * 3 });

// 方法二:使用svg渲染,这个效果更好,就是需要调整grid,不然图表不完整

// echarts.init(chartDom, null, { renderer: "svg" })



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。