uniapp(vue)生成PDF

因业务需求,需要由前端来生成PDF,之前是后端生成的PDF,不够美化,所以我就在网上找了找实现方式,基本上全部都是由html2canvas和jspdf生成的,实现方式都是由html2canvas将页面转换成canvas图片,然后jspdf根据图片生成PDF。

然后自己也按照网上的尝试了一番,最后发现无法按照自己的需求正常分页,之后自己又查了一堆,百度了好久,最后自己终于算是成功做出了可以按照自己需求分页的功能。

前面的步骤都是一样的,先安装html2canvas和jspdf

npm install html2canvas --save
npm install jspdf --save

创建一个pdf.js的文件

// 创建 pdf.js
// 引入依赖
import Vue from 'vue'
import html2canvas from 'html2canvas'
import JsPDF from 'jspdf'

const PDF = {}
PDF.install = function (Vue, options) {
  /**
   * targetDom: 需要打印的dom对象
   * name:pdf的名字
   * callback: 回调函数
   */
Vue.prototype.$createPdf = function (targetDom, name, callback) {
	// a4纸的尺寸[592.28,841.89]
	const A4_WIDTH = 592.28
	const A4_HEIGHT = 841.89
	// 每页pdf 相对于A4纸张的页面所对应的高度
	let pageHeight = targetDom.scrollWidth / A4_WIDTH * A4_HEIGHT
	//将dom对象复制一份出来,我们要对dom对象的大小进行调整,不能影响原页面dom对象的样式
    let cloneDom = targetDom.cloneNode(true)
    cloneDom.style.width = targetDom.scrollWidth + 'px'
    cloneDom.style.background = '#FFFFFF'
    document.body.appendChild(cloneDom)
	//这里划重点,将页面中的预计生成一页的div设置一个单独的class,然后根据class获取到所有的节点,即可大致知道将要生成多少页的PDF
	let pages = cloneDom.childNodes
	//遍历一次这些节点
	for (let i = 0; i < pages.length; i++) {
		//判断每个页面的节点对象,高度是否大于或小于实际的PDF的高度,如果大于PDF每页的高度,那这个节点最少也要生成2页的PDF,切不能影响下面的节点的,用节点对象的高度/PDF每页的高度,向上取整获取到倍数,然后设置该节点的高度为:PDF每页的高度*倍数,如果节点高度小于PDF每页的高度,直接将该节点高度设置成PDF每页的高度即可
		if(pages[i].offsetHeight > pageHeight){
			let num = Math.ceil(pages[i].offsetHeight / pageHeight)
			pages[i].style.height = pageHeight * num + 'px'
		}else{
			pages[i].style.height = pageHeight + 'px'
		}
		//页面中每页的div之间有间隔,将这个间隔去掉
		pages[i].style.marginBottom = 0 + 'px'
	}
    html2canvas(cloneDom, {
      scale: 1, // 提升画面质量,但是会增加文件大小
      useCORS: true, // 允许跨域图片 当图片是链接地址时,需加该属性,否组无法显示图片
      imageTimeout: 0, // 图片加载延迟,默认延迟为0,单位毫秒
      height: cloneDom.scrollHeight, // canvas的高度设定,这里的宽高要用复制出来的dom对象的宽高,不能用原dom对象,因为我们已经将dom的高度整体拉高了
      width: cloneDom.scrollWidth, // canvas的宽度设定
      dpi: window.devicePixelRatio * 1, // 将分辨率提高到特定的DPI
    }).then(canvas => {
      document.body.removeChild(cloneDom)
      let contentWidth = canvas.width
      let contentHeight = canvas.height
      let pageData = canvas.toDataURL('image/jpeg', 1.0)
      // 未生成pdf的html页面高度
      let leftHeight = contentHeight
      // 页面偏移
      let position = 0
      // html页面生成的canvas在pdf中图片的宽高
      let imgWidth = A4_WIDTH
      let imgHeight = A4_WIDTH / contentWidth * contentHeight
      // 设置pdf的尺寸,pdf要使用pt单位 已知 1pt/1px = 0.75   pt = (px/scale)* 0.75
      let pdf = new JsPDF('', 'pt', 'a4')
      // 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度
      // 当内容未超过pdf一页显示的范围,无需分页
      if (leftHeight < pageHeight) {
        pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
      } else {
        while (leftHeight > 0) {
          pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
          leftHeight -= pageHeight
          position -= A4_HEIGHT
          // 避免添加空白页
          if (leftHeight > 0) {
            pdf.addPage()
          }
        }
      }
      // 直接下载
      pdf.save(name + '.pdf') 
    })
  }
}
Vue.use(PDF)
export default PDF

在main.js中引用pdf.js文件

import htmlToPdf from '@/common/pdf.js'

Vue.use(htmlToPdf)

在页面上使用

//在vue中用ref获取dom对象,在uniapp中用id获取dom对象,子元素为预计生成的每页PDF,这里就是每个page为一页
<view ref="targetDom" id="targetDom">
    <view class="page"></view>
	<view class="page"></view>
	<view class="page"></view>
	<view class="page"></view>
	<view class="page"></view>
</view>


//js
//let target = this.$refs.targetDom //用ref获取节点对象
let target = document.querySelector('#targetDom')   //ID获取节点对象
this.$createPdf(target, '文件名')

评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值