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的边距,显示区域190x277let 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].clientHeightreturn 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的高度计算公式