使用jspdf将html页面生成pdf文件

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的高度计算公式
在这里插入图片描述

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值