一、问题
一开始的时候,准备使用html2canvas+jspdf来实现的,但是遇到了一个麻烦的问题,在其他项目中使用html2canvas没有任何问题,但是在要开发的项目中使用,就给我报错,是真滴烦。
html2canvas报错
Uncaught (in promise) unable to find element in cloned iframe.
在github也看了很多,但是也没找到最终的解决办法。
html2canvas
这个错弄的人都炸裂了,当然html2canvas+jspdf的方法我还是想分享一下,当然这套代码是可以用的(但是在你的项目不一定能用):
npm i html2canvas jspdf
html2pdf.js
import html2Canvas from 'html2canvas';
import JsPDF from 'jspdf';
/**
* [获取页面导出的pdf文件]
* @param {[Object]} options [导出pdf配置项,包括一个title属性设置文件名,以及query属性设置获取元素的条件]
*/
function getPdf(options) {
var title = options.title || '标题';// 导出文件名,默认为“标题”
const children = document.getElementsByClassName(options.className || 'pdf-content');
let canvas = [];
let i = 0;
function toCanvas() {
// if (children.length > 1) {
html2Canvas(children[i], {
dpi: 500, // 导出pdf清晰度
background: '#fff', // 背景设为白色(默认为黑色)
scale: 2,
logging: false,
useCORS: true,
}).then(res => {
// 计算每个dom的高度,方便后面计算分页
res.imgWidth = 592.28;
res.imgHeight = 592.28 / res.width * res.height;
canvas.push(res);
i++;
if (canvas.length === children.length) {
paging();
toPdf();
} else {
toCanvas();
}
});
// }
}
/**
* [根据dom的高度初步进行分页,会将canvas组装为一个二维数组]
*/
function paging() {
const imgArr = [[]];
let pageH = 0; // 页面的高度
let allH = 0; // 当前组所有dom的高度和
let j = 0;
for (let k = 0; k < canvas.length; k++) {
// 涉及到k--的操作,使用for循环方便
pageH += canvas[k].imgHeight;
if (pageH > 841.89 && canvas[k].imgHeight < 841.89) {
// 当某个页面装不下下一个dom时,则分页
imgArr[j][0].allH = allH - canvas[k].imgHeight;
allH = pageH = 0;
k--;
j++;
imgArr.push([]);
} else {
if (canvas[k].imgHeight > 841.89) {
// 特殊情况:某个dom高度大于了页面高度,特殊处理
canvas[k].topH = 841.89 - (pageH - canvas[k].imgHeight); // 该dom顶部距离页面上方的距离
pageH = (2 * canvas[k].imgHeight - pageH) % 841.89;
canvas[k].pageH = pageH; // 该dom底部距离页面上方的距离
}
imgArr[j].push(canvas[k]);
allH += canvas[k].imgHeight;
}
if (k === canvas.length - 1) imgArr[j][0].allH = allH;
}
canvas = imgArr;
}
/**
* [生成PDF文件]
*/
function toPdf() {
const PDF = new JsPDF('', 'pt', 'a4');
canvas.forEach((page, index) => {
let allH = page[0].allH;
let position = 0;// pdf页面偏移
if (index !== 0 && allH <= 841.89) PDF.addPage();
page.forEach(img => {
if (img.imgHeight < 841.89) {
// 当某个dom高度小于页面宽度,直接添加图片
PDF.addImage(img.toDataURL('image/jpeg', 1.0), 'JPEG', 0, position, img.imgWidth, img.imgHeight);
position += img.imgHeight;
allH -= img.imgHeight;
} else {
// 当某个dom高度大于页面宽度,则需另行处理
while (allH > 0) {
PDF.addImage(img.toDataURL('image/jpeg', 1.0), 'JPEG', 0, position, img.imgWidth, img.imgHeight);
allH -= img.topH || 841.89;
position -= img.topH || 841.89;
img.topH = 0;
if (allH > 0) PDF.addPage();
}
position = img.pageH;
}
});
});
PDF.save(title + '.pdf');
}
toCanvas();
}
export default getPdf;
使用:
import getPdf from './html2pdf'
getPdf({
className: "dom的类名", title: "下载pdf的文件名" });
html-to-image
html2canvas报错,还找不到解决办法我也是难受的一批,于是找到了它的替代方案
这个替代方案主要用户将html元素转成各种图片类型,不过里面的方法确实很多。
html-to-image 是一个使用 HTML5 canvas 和 SVG 从 DOM 节点生成图像的工具。
npm install --save html-to-image
用法
/* ES6 */
import * as htmlToImage from 'html-to-image';
import {
toPng, toSvg, toJpeg, toBlob, toCanvas, toPixelData } from 'html-to-image';
/* ES5 */
var htmlToImage = require('html-to-image');
toJpeg
保存并下载压缩的 JPEG 图像:
htmlToImage.toJpeg(document.getElementById('my-node'), {
quality: 0.95 })
.then(function (dataUrl) {
var link = document.createElement('a');
link.download = 'my-image-name.jpeg';
link.href = dataUrl;
link.click();
});
toCanvas
htmlToImage.toCanvas(document.getElementById('my-node'))
.then(function (canvas) {
document.body.appendChild(canvas);
});
我们就是要使用toCanvas这个方法,将他转成canvas元素然后再结合jspdf进行下载pdf文件
自己使用:
npm i html-to-image jspdf
import {
toPng, toJpeg, toBlob, toPixelData, toSvg, toCanvas } from 'html-to-image';
import jsPDF from 'jspdf';
toCanvas(dom节点)
.then(function (canvas) {
// document.body.appendChild(canvas);
var contentWidth = canvas.width;
var contentHeight = canvas.height;
//一页pdf显示html页面生成的canvas高度;
var pageHeight = contentWidth / 592.28 * 841.89;
//未生成pdf的html页面高度
var leftHeight = contentHeight;
//页面偏移
var position = 0;
//a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
var imgWidth = 595.28;
var imgHeight = 592.28 / contentWidth * contentHeight;
var pageData = canvas.toDataURL('image/jpeg', 1.0);
var pdf = new jsPDF('', 'pt', 'a4');
//有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
//当内容未超过pdf一页显示的范围,无需分页
if (leftHeight < pageHeight) {
console.log(imgWidth, imgHeight, 'imgWidth, imgHeight')
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(`xxxxxx.pdf`);
}).catch((err) => {
console.log(err)
message.warning("导出PDF失败")
});
效果: