使用React+html2canvas + jspdf实现生成pdf文件
1. 安装插件
先安装第一个html2canvas插件,作用是实现将html页面转换成图片
安装命令如下:
npm install --save html2canvas || npm install html2canvas
然后安装第二个插件jspdf,作用是将图片转为pdf
安装命令如下:
npm install jspdf --save || npm install jspdf
2. 导入html2canvas和jspdf插件到项目中
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';
3. 定义一个div和需要生成pdf的页面 (或者给需要到处的页面元素最外层加id)
<div id="demo">
<div style={{marginTop:15}}>
<div>
此为到处的pdf文件
</div>
</div>
</div>
4. 定义一个触发生成pdf文件的按钮
<Button onClick={download}>生成报告</Button>
5. 实现download方法之一
download = () => {
const element = document.getElementById('demo'); // 这个dom元素是要导出的pdf的div容器
const w = element.offsetWidth; // 获得该容器的宽
const h = element.offsetHeight; // 获得该容器的高
const offsetTop = element.offsetTop; // 获得该容器到文档顶部的距离
const offsetLeft = element.offsetLeft; // 获得该容器到文档最左的距离
const canvas = document.creatElement("canvas");
let abs = 0;
const win_i = document.body.clientWidth; // 获得当前可视窗口的宽度(不包含滚动条)
const win_o = window.innerWidth; // 获得当前窗口的宽度(包含滚动条)
if(win_o > win_i){
abs = (win_o - win_i) / 2; // 获得滚动条宽度的一半
}
canvas.width = w * 2; // 将画布宽&&高放大两倍
canvas.height = h * 2;
const context = canvas.getContext('2d');
context.scale(2, 2);
context.translate(-offsetLeft - abs, -offsetTop);
// 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此translate的时候,要把这个差值去掉
html2canvas(element, {
allowTaint: true,
scale: 2 // 提升画面质量,但是会增加文件大小
}).then( canvas => {
const contentWidth = canvas.width;
const contentHeight = canvas.height;
// 一页pdf显示html页面生成的canvas高度
const pageHeight = contentWidth / 592.28 * 841.89;
// 未生成pdf的html页面高度
const leftHeight = contentHeight;
// 页面偏移
const position = 0;
// a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
const imgWidth = 595.28;
const imgHeight = 592.28 / contentWidth * contentHeight;
const pageDate = canvas.toDataURL('image/jpeg', 1.0);
const pdf = new jsPDF('', 'pt', 'a4');
// 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面的高度(841.89)
// 当内容未超过pdf一页显示的范围,无需分页
if(leftHeight < pageHeight) {
pdf.addImage(pageDate,'JPEG', 0, position, imgWidth, imgHeight);
}else { // 分页
while (leftHeight > 0){
pdf.addImage(pageDate, 'JPEG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight;
position -= 841.89;
// 避免添加空白页
if(leftHeight > 0){
pdf.addPage()
}
}
}
pdf.save('你的名字.pdf');
})
}
方法二:
download = () => {
const element = document.getElementById('demo');
const imgHeight = element.clientHeight;
const imgWidth = element.clientWidth;
const scale = 3;
html2canvas(element, {
letterRendering: true,
allowTaint: true,
taintTest: false,
height: imgHeight,
// 为了使横向滚动条的内容全部展示,这里必须指定
width: imgWidth,
backgroundColor: '#fff',
scale: scale, // 提升画面质量,但是会增加文件大小,
onclone: (element) => {
const inputs = element.getElementsByTagName("input")
let inputList = Array.prototype.slice.call(inputs);
inputList.map((item)=>{
if(item.placeholder){
item.removeAttribute("placeholder")
}
})
let selectHolder = detail.querySelectorAll(".ant-select-selection-placeholder")
let selectHolderList = Array.prototype.slice.call(selectHolder)
selectHolderList.map((item)=>{
item.style.display = "none"
})
// detail.getElementById("campaignInfo_targetGroupDescription").removeAttribute("placeholder")
// onclone logic to resize div
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
},500)
})
}
}).then((canvas) => {
const pageData = canvas.toDataURL('image/jpeg', 1);
// 设置pdf的尺寸,pdf要使用pt单位 已知 1pt/1px = 0.75 pt = (px/scale)* 0.75
// scale为上面的scale 缩放了scale倍, 60为pdf四周留白
let pdfX = (imgWidth + 60) / scale * 0.75
let pdfY = (imgHeight + 60) / scale * 0.75
let imgX = (imgWidth / scale * 0.75)
let imgY = (imgHeight / scale * 0.75); //内容图片这里不需要留白的距离
// pdfX,pdfY为pdf的大小,imgX,imgY为内容图片的大小
let PDF = new jsPDF('', 'pt', [pdfX, pdfY])
// 7.5 为坐标,让img在pdf中水平垂直居中,四周留白均匀
PDF.addImage(pageData, 'JPEG', 7.5, 7.5, imgX, imgY);
//获取当前时间戳
let timestmp = new Date().getTime()
PDF.save(`cmt_campaign_basic_info_${lib.dataFormat(timestmp)}.pdf`);
this.campaignDetailStore.pdfLoadingVisible = false
// this.setState({
// pdfimg:pageData
// })
}).catch(() => {
this.campaignDetailStore.pdfLoadingVisible = false
// this.setState({ exportPDF: false });
});
};