项目开发过程中有导出当前的页面为pdf的功能,为了减少服务器压力,所以由前端结合html2canvas和jspdf2个库来实现前端导出pdf。
基本思路
- 使用html2canvas将对应的DOM节点生成canvas
- 通过jspdf库将canvas生成pdf
- 最后下载pdf
通过DOM节点生成canvas
/**
* @param elId 打印的节点ID
*/
async function getCanvasByHtmlId(elId) {
let canvas = await html2canvas(document.getElementById(elId), {
scale: 2,
useCORS: true,
allowTaint: true,
taintTest: false,
imageTimeout: 0
}).then(canvas => {
return canvas;
});
return canvas;
}
通过canvas创建pdf
/**
* @param htmlCanvas canvas对象
*/
function canvasToPdf(htmlCanvas) {
let canvasWidth = htmlCanvas.width;
let canvasHeight = htmlCanvas.height;
let imgBase64 = htmlCanvas.toDataURL("image/jpeg", 1.0);
//a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
let imgWidth = 595.28;
//图片高度需要等比缩放
let imgHeight = 595.28 / canvasWidth * canvasHeight;
let pageHeight = imgHeight; //pdf转化后页面总高度
let position = 0;
let pdfInstance = new jspdf("", "pt", "a4");
pdfInstance.setFontSize(12);
if (imgHeight < 841.89) {
pdfInstance.addImage(imgBase64, "JPEG", 0, 0, imgWidth, imgHeight);
} else {
while (pageHeight > 0) {
pdfInstance.addImage(imgBase64, "JPEG", 0, position, imgWidth, imgHeight);
pageHeight -= 841.89;
position -= 841.89;
if (pageHeight > 0) {
pdfInstance.addPage();
}
}
}
return pdfInstance;
}
下载pdf
function downPdf(pdfInstance, title) {
// 文件名过长导致下载失败
if (title.length > 50) {
title = title.substring(title.length - 50);
}
pdfInstance.save(title + ".pdf", { returnPromise: true }).then(function() {
//搜狗浏览器下载机制问题暂时不关闭
if (!(navigator.userAgent.toLowerCase().indexOf("se 2.x") > -1)) {
setTimeout(window.close, 300);
}
});
}
整体代码如下
import html2canvas from "html2canvas";
import jspdf from "jspdf";
/**
* @param title pdf文件名
* @param elId 打印的节点ID
*/
async function htmlToPdf(title = "文件", elId) {
if (!elId) {
console.error("导出节点不存在!");
return;
}
//将html dom节点生成canvas
let htmlCanvas = await getCanvasByHtmlId(elId);
// 将canvas对象转为pdf
let pdf = canvasToPdf(htmlCanvas);
// 通过浏览器下载pdf
downPdf(pdf, title);
}
/**
* @param elId 打印的节点ID
*/
async function getCanvasByHtmlId(elId) {
let canvas = await html2canvas(document.getElementById(elId), {
scale: 2,
useCORS: true,
allowTaint: true,
taintTest: false,
imageTimeout: 0
}).then(canvas => {
return canvas;
});
return canvas;
}
/**
* @param htmlCanvas canvas对象
*/
function canvasToPdf(htmlCanvas) {
let canvasWidth = htmlCanvas.width;
let canvasHeight = htmlCanvas.height;
let imgBase64 = htmlCanvas.toDataURL("image/jpeg", 1.0);
//a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
let imgWidth = 595.28;
//图片高度需要等比缩放
let imgHeight = 595.28 / canvasWidth * canvasHeight;
let pageHeight = imgHeight; //pdf转化后页面总高度
let position = 0;
let pdfInstance = new jspdf("", "pt", "a4");
pdfInstance.setFontSize(12);
if (imgHeight < 841.89) {
pdfInstance.addImage(imgBase64, "JPEG", 0, 0, imgWidth, imgHeight);
} else {
while (pageHeight > 0) {
pdfInstance.addImage(imgBase64, "JPEG", 0, position, imgWidth, imgHeight);
pageHeight -= 841.89;
position -= 841.89;
if (pageHeight > 0) {
pdfInstance.addPage();
}
}
}
return pdfInstance;
}
function downPdf(pdfInstance, title) {
// 文件名过长导致下载失败
if (title.length > 50) {
title = title.substring(title.length - 50);
}
pdfInstance.save(title + ".pdf", { returnPromise: true }).then(function() {
//搜狗浏览器下载机制问题暂时不关闭
if (!(navigator.userAgent.toLowerCase().indexOf("se 2.x") > -1)) {
setTimeout(window.close, 300);
}
});
}
export default htmlToPdf;