1、下载jspdf插件包
npm i jspdf
2、在utils文件夹下创建一个单独的文件(名字无具体要求)
// 页面导出为pdf格式,title表示为下载的标题,html表示要下载的页面
import html2Canvas from 'html2canvas' // 不用单独去下载这个包,下载jspdf包时就已经下载下来了,所以直接用就可以了
import JsPDF from 'jspdf'
import { Loading } from 'element-ui'
let noTableHeight = 0; //table外的元素高度
function htmlPdf(title, html, lableList, type) {// type传有效值pdf则为横版
const loading = Loading.service({
lock: true,
text: '正在生成PDF文件',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
if (lableList) {
const pageHeight = Math.floor(277 * html.scrollWidth / 190); //计算pdf高度
for (let i = 0; i < lableList.length; i++) { //循环获取的元素
const multiple = Math.ceil((lableList[i].offsetTop + lableList[i].offsetHeight) / pageHeight); //元素的高度
if (isSplit(lableList, i, multiple * pageHeight)) { //计算是否超出一页
let _H = '' //向pdf插入空白块的内容高度
_H = multiple * pageHeight - (lableList[i].offsetTop + lableList[i].offsetHeight);
let newNode = getFooterElement(_H); //向pdf插入空白块的内容
const divParent = lableList[i].parentNode; // 获取该div的父节点
const next = lableList[i].nextSibling; // 获取div的下一个兄弟节点
// 判断兄弟节点是否存在
if (next) {
// 存在则将新节点插入到div的下一个兄弟节点之前,即div之后
divParent.insertBefore(newNode, next);
} else {
// 否则向节点添加最后一个子节点
divParent.appendChild(newNode);
}
}
}
}
html2Canvas(html, {
allowTaint: false,
taintTest: false,
logging: false,
useCORS: true,
dpi: window.devicePixelRatio * 1,
scale: 4 // 按比例增加分辨率,图片模糊时数值调高点
}).then(canvas => {
let pdf = new JsPDF('p', 'mm', 'a4'); // A4纸,纵向
let ctx = canvas.getContext('2d');
let a4w = type ? 277 : 190; let a4h = type ? 190 : 277; // A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
let imgHeight = Math.floor(a4h * canvas.width / a4w); // 按A4显示比例换算一页图像的像素高度
let renderedHeight = 0;
while (renderedHeight < canvas.height) {
let page = document.createElement('canvas');
page.width = canvas.width;
page.height = Math.min(imgHeight, canvas.height - renderedHeight);// 可能内容不足一页
// 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0);
pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width)); // 添加图像到页面,保留10mm边距
renderedHeight += imgHeight;
if (renderedHeight < canvas.height) {
pdf.addPage();// 如果后面还有内容,添加一个空页
}
// delete page;
}
loading.close()
// 保存文件
pdf.save(title + '.pdf');
});
}
// pdf截断需要一个空白位置来补充
function getFooterElement(remainingHeight, fillingHeight = 0) {
const newNode = document.createElement('div');
newNode.style.background = '#ffffff';
newNode.style.width = 'calc(100% + 8px)';
newNode.style.marginLeft = '0px';
newNode.style.marginBottom = '0px';
newNode.classList.add('divRemove');
newNode.style.height = (remainingHeight + fillingHeight) + 'px';
return newNode;
}
// 计算是否超出一页
function isSplit(nodes, index, pageHeight) {
noTableHeight+= nodes[index].clientHeight
return nodes[index].offsetTop + nodes[index].offsetHeight < pageHeight && nodes[index + 1] && nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight > pageHeight;
}
export default htmlPdf;
<el-button type="primary" @click="exportReport">输出报表</el-button>
<div class="output-report-pdf" ref="outputReportPDF" v-if="outputReportPDFShow">
<div class="pdf-item" ref="outputReportPDFItem" v-for="(item, index) in reportPdfData" :key="index" :style="(index + 1) % 2 !== 0 ? 'border-bottom: none': ''">
<div class="output-report-img">
<el-image style="width: 100%; height: 100%" :src="item.img" fit="contain" @load="handleImage(index)"></el-image>
</div>
</div>
</div>
<script>
// 引入刚才创建的文件
import htmlPdf from '@/utils/htmlToPdf'
data() {
return {
outputReportPDFShow: false
}
},
methods: {
exportReport() {
this.reportPdfData = '从后端获取到的数据'
this.outputReportPDFShow = true
},
// el-image加在完图片时触发
handleImage(index) {
// 等最后一张图片在页面中加在完再输出成pdf,要不然pdf文件里的图片会不显示
if (index + 1 === this.reportPdfData.length) {
const name = '测试'
// name:保存的文件名称;this.$refs.outputReportPDF:要输出成pdf的总模块;this.$refs.outputReportPDFItem:总模块中的每个item,用于判断是否需要在换页时加个空白框隔开
htmlPdf(name, this.$refs.outputReportPDF, this.$refs.outputReportPDFItem)
this.outputReportPDFShow = false
}
}
}
</script>
<style scoped lang="scss">
.output-report-pdf {
.pdf-item {
// 其它样式根据具体要求设置,但是每个小模块的宽高有要求,因为要计算小模块是否需要放到下一页显示
width: 570px; // pdf的高度:277 * width / 190, width最好是190的倍数;出现小数时容易出错
height: 415px; // 高度最好不要超过一页pdf的高度
border: 1px solid #000000;
.output-report-img {
width: 100%;
height: 100%;
}
}
}
</style>
每页pdf的高度计算公式