html转PDF
我的需求是 自动生成证书 并导出 pdf, 在网上大家都说用这两个插件,经过测试使用,也遇到了问题,就记录一下遇到的问题。
1,下载插件模块
npm install html2canvas jspdf --save
2,定义功能实现方法
在项目工具方法存放文件夹utils中创建htmlToPdf.js
文件,我的代码如下,我这里包含了图片下载,不需要的去掉就好:
// 导出页面为PDF格式
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
export default {
install(Vue, options) {
Vue.prototype.getPdf = function () {
var title = this.htmlTitle // 导出名称
var type = this.downType // 导出类型 true ->图片 false-> pdf
var htmlID = document.getElementById('pdfDom')
// window.pageYoffset = 0; // 如果有滚动条影响,会导致导出的内容不全,可以直接设置导出前置顶
// document.documentElement.scrollTop = 0;
// document.body.scrollTop = 0;
html2Canvas(htmlID, {
allowTaint: true,
// scrollY: 50, // 偏移量吧,如果有滚动条影响,但是不想设置滚动条置顶, 可以设置这个,但是要计算滚动了多少
// scrollX:0,
// x:0, // 距离左边距离
// y:10,
// width: 1000,
// height: 800
// 下面两个用来提高清晰度
dpi: window.devicePixelRatio*4, //将分辨率提高到特定的DPI 提高四倍
scale:4, //按比例增加分辨率
useCORS: true // 【重要】开启跨域配置
}).then(function (canvas) {
let contentWidth = canvas.width
let contentHeight = canvas.height
//一页pdf显示html页面生成的canvas高度
let pageHeight = contentWidth / 592.28 * 841.89
//未生成pdf的html页面高度
let leftHeight = contentHeight
//页面偏移
let position = 0
let imgWidth = 592.28
//a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
// let imgHeight = 592.28 / contentWidth * contentHeight
let imgHeight = 592.28 / contentWidth * contentHeight
// 1.0 清晰度0-1
let pageData = canvas.toDataURL('image/jpeg', 1.0)
if(type) {
// 生成图片
//创建一个 a 标签,并设置 href 和 download 属性
const el = document.createElement("a");
// 设置 href 为图片经过 base64 编码后的字符串,默认为 png 格式
el.href = pageData;
el.download = title;
// 创建一个点击事件并对 a 标签进行触发
const event = new MouseEvent("click");
el.dispatchEvent(event);
} else {
// 生成 pdf
//有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
//当内容未超过pdf一页显示的范围,无需分页
// l 横向 默认竖向
let PDF = new JsPDF('l', 'pt', 'a4')
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')
}
})
}
}
}
3, 全局引入实现方法
在项目主文件main.js
中引入定义好的实现方法,并注册。
import htmlToPdf from '@/components/utils/htmlToPdf'
// 使用Vue.use()方法就会调用工具方法中的install方法
Vue.use(htmlToPdf)
4, 在相关要导出的页面中,点击时调用绑定在Vue原型上的getPdf方法,传入id即可
//html
<div id="pdfDom">
<!-- 要下载的HTML页面,页面是由后台返回 -->
<div v-html="pageData"></div>
</div>
<el-button type="primary" size="small" @click="getPdf('#pdfDom')">点击下载</el-button>
//js
export default {
data () {
return {
htmlTitle: '页面导出PDF文件名',
downType: true
}
}
}
下面是我遇到的问题:
1. 导出内容不全 ?
说明: 我导出的是一个证书模板,没有分页, 但是页面有滚动。
原因:页面滚动导致导出不全, 因为这个插件会把 滚动出去的部分也算进来,而不是单单 我们· <div id="pdfDom> 这里的内容
解决: 所以,如果有滚动条,可以到出前先置顶,去掉滚动条,或者计算滚动了多少,配置一下 滚动参数, 我代码里有,大家可以看看,和测试
// window.pageYoffset = 0; // 如果有滚动条影响,会导致导出的内容不全,可以直接设置导出前置顶
// document.documentElement.scrollTop = 0;
// document.body.scrollTop = 0;
//配置这两个
// scrollY: 50, // 偏移量吧,如果有滚动条影响,但是不想设置滚动条置顶, 可以设置这个,但是要计算滚动了多少
// scrollX:0,
2.留边问题
一开始我想的是配置 x,y 距离页面的距离, 可是这样会导致内容移动,显示不全
解决: 直接设置 <div id="pdfDom> 样式就好了, 因为按 html 导出的, 设置padding吧
- 经测试,放在element的Dialog组件显示的dom ,滚动条不影响内容导出,我是这样做的哈哈,下面我放上我证书生成导出demo , 大家可以参考