主要就3个方法 exportReport outPutPdfFn isSplit
前置操作,我在vue原型上挂载了getPdf方法,方便复用
// 导出页面为PDF格式
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
Vue.prototype.getPdf = function (title, dom, emptyDomId) {
// 注册getPdf方法,传入两个参数,此处使用了promise处理导出后的操作
/*
title: 导出文件名
dom: 需要导出dom的id
*/
return new Promise((resolve, reject) => {
html2Canvas(dom, {
useCORS: true, // 由于打印时,会访问dom上的一些图片等资源,解决跨域问题!!重要
allowTaint: true // 允许跨域
}).then(canvas => {
const contentWidth = canvas.width
const contentHeight = canvas.height
// 根据A4纸的大小,计算出dom相应比例的尺寸
const pageHeight = contentWidth / 592.28 * 841.89
let leftHeight = contentHeight
let position = 0
const imgWidth = 595.28
// 根据a4比例计算出需要分割的实际dom位置
const imgHeight = 592.28 / contentWidth * contentHeight
// canvas绘图生成image数据,1.0是质量参数
const pageData = canvas.toDataURL('image/jpeg', 1.0)
// a4大小
const PDF = new JsPDF('', 'pt', 'a4')
// 当内容达到a4纸的高度时,分割,将一整块画幅分割出一页页的a4大小,导出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 -= 841.89
if (leftHeight > 0) {
PDF.addPage()
}
}
}
// 导出
PDF.save(title + '.pdf')
// 删除添加的空div
const emptyDom = document.getElementById(emptyDomId)
emptyDom.remove()
resolve(true)
})
.catch(() => {
reject(false)
})
})
}
1 首先template部分就是,给你要到处pdf内容的部分加上一个id标识,用于获取这个盒子的dom对象,如图我这里的id是pdfDom
2 接着就是第一个方法exportReport,也就是按钮触发的方法,这个方法里面很简单,就获取了pdfDom这个盒子的dom对象,然后调用生成pdf的方法outPutPdfFn
exportReport() {
const target = document.getElementById('pdfDom')
this.outPutPdfFn('pdf文件名', target, 'item')
},
3 下面就是主要生成pdf文件的函数
outPutPdfFn(title, target, itemClass) {
const vm = this
const A4_WIDTH = 592.28
const A4_HEIGHT = 841.89
vm.$nextTick(() => {
// dom的id。
const pageHeight = target.scrollWidth / A4_WIDTH * A4_HEIGHT
// 获取分割dom,此处为class类名为item的dom
const lableListID = document.getElementsByClassName(itemClass)
// 进行分割操作,当dom内容已超出a4的高度,则将该dom前插入一个空dom,把他挤下去,分割
for (let i = 0; i < lableListID.length; i++) {
const multiple = Math.ceil((lableListID[i].offsetTop + lableListID[i].offsetHeight) / pageHeight)
if (this.isSplit(lableListID, i, multiple * pageHeight)) {
const divParent = lableListID[i].parentNode // 获取该div的父节点
const newNode = document.createElement('div')
newNode.className = 'emptyDiv'
newNode.id = 'emptyDiv'
newNode.style.background = '#ffffff'
const _H = multiple * pageHeight - (lableListID[i].offsetTop + lableListID[i].offsetHeight)
newNode.style.height = _H + 30 + 'px'
newNode.style.width = '100%'
const next = lableListID[i].nextSibling // 获取div的下一个兄弟节点
// 判断兄弟节点是否存在
console.log(next)
if (next) {
// 存在则将新节点插入到div的下一个兄弟节点之前,即div之后
divParent.insertBefore(newNode, next)
} else {
// 不存在则直接添加到最后,appendChild默认添加到divParent的最后
divParent.appendChild(newNode)
}
}
}
// 传入title和dom标签,此处是 #content
// 异步函数,导出成功后处理交互
this.getPdf(title, target, 'emptyDiv').then(() => {
// 自定义等待动画关闭
this.$message({
type: 'success',
message: '导出成功'
})
this.detailSHow = false
})
this.$nextTick(() => {
const emptyDom = document.getElementById('emptyDiv')
emptyDom.remove()
})
})
},
4 生成pdf函数中还涉及到了一个是否切割的函数判断,如下
isSplit(nodes, index, pageHeight) {
// 计算当前这块dom是否跨越了a4大小,以此分割
if (nodes[index].offsetTop + nodes[index].offsetHeight < pageHeight && nodes[index + 1] && nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight > pageHeight) {
return true
}
return false
},
至此一个简单的生成pdf功能就实现了,上述的方法基本都封装好了,使用上述的3个方法,只需要自己对需要生成pdf内容的盒子进行id的添加,将方法带入就可以了。