方式一:使用html2canvas和jspdf插件实现
该方式是通过html2canvas将HTML页面转换成图片,然后再通过jspdf将图片的base64生成为pdf文件。
缺点:
- 生成的pdf质量不高,失真比较严重;
- 在分页处如果有图片的话,不会自动识别隔页处理(甚至一行文字也能给你上下一分为二),而是无情地把图片一分为二。
实现步骤如下:
1.安装插件 ==jspdf html2canvas==
第一个.将页面html转换成图片
npm install --save html2canvas
第二个.将图片生成pdf
npm install jspdf --save
2、创建htmlToPdf.js文件。(‘src/scripts/common/utils/htmlToPdf’)’
分页处理:
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
export default {
install (Vue, options) {
Vue.prototype.getPdf = function (idStr, title) {
html2Canvas(document.querySelector('#' + idStr), {
// allowTaint: true,
useCORS: true,
// scale: 2, // 提升画面质量,但是会增加文件大小
}).then((canvas) => {
const contentWidth = canvas.width
const contentHeight = canvas.height
// 一页pdf显示html页面生成的canvas高度;
const pageHeight = contentWidth / 592.28 * 841.89
// 生成pdf的html页面高度
let leftHeight = contentHeight
// 页面偏移
let position = 0
// a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
const imgWidth = 595.28
const imgHeight = 592.28 / contentWidth * contentHeight
// canvas.crossOrigin="anonymous";
const pageData = canvas.toDataURL('image/jpeg', 1.0)
const PDF = new JsPDF('', 'pt', 'a4')
// 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
// 当内容未超过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')
})
}
},
}
不分页处理:
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
export default {
install (Vue, options) {
Vue.prototype.getPdf = function (idStr, title) {
html2Canvas(document.querySelector('#' + idStr), {
// allowTaint: true,
useCORS: true,
// scale: 2, // 提升画面质量,但是会增加文件大小
}).then((canvas) => {
const contentWidth = canvas.width
const contentHeight = canvas.height
/* 导出不分页处理 */
const pageData = canvas.toDataURL('image/jpeg', 1.0)
const pdfWidth = (contentWidth + 10) / 2 * 0.75
const pdfHeight = (contentHeight + 200) / 2 * 0.75 // 500为底部留白
const imgWidth = pdfWidth
const imgHeight = (contentHeight / 2 * 0.75) // 内容图片这里不需要留白的距离
const PDF = new JsPDF('', 'pt', [ pdfWidth, pdfHeight, ])
PDF.addImage(pageData, 'jpeg', 0, 0, imgWidth, imgHeight)
PDF.save(title + '.pdf')
})
}
},
}
3, 全局引入实现方法
在项目主文件中引入定义好的实现方法,并注册
import htmlToPdf from '@/scripts/common/utils/htmlToPdf'
// 使用Vue.use()方法就会调用工具方法中的install方法
Vue.use(htmlToPdf)
4, 在相关要导出的页面中,点击时调用绑定在Vue原型上的getPdf方法,传入id即可
<div id="pdfDom">
//给自己需要导出的ui部分.定义id为"pdfDom".此部分将就是pdf显示的部分
</div>
<el-button @click="export">导出PDF</el-button>
export default {
data () {
return {
fileName: '页面导出PDF文件名'
}
}
methods:{
export () {
this.getPdf('pdfDom', this.fileName)
}
}
}
问题:
分页:jspdf需要使用高度较小的图片,图片高度越小,分页效果就越好。
pdf清晰度:如果利用了echart之类,一定要用它给的api获取dataURL,设置分辨率倍数多一点,导出的图片非常清晰,这样生产的pdf才会清晰。如果是普通元素,如果发现导出的图片不够清晰,可以专门写一个用于导出的页面。此页面所有内容都放大2 倍,然后设置left:-9999隐藏(==不可display:none==)。当html2canvas转换此页面的为图片的时候,图片会非常大,然后使用pdf编辑工具让图片等比缩放,会很清晰。html2canvas option里也有个scale参数,也可以调,但太大会报错。
方式二:调用浏览器自身的方法。
window.print() 来打印(打印时可选下载),打印比较清晰,但存在浏览器兼容问题,适用于谷歌。