最近刚完成了项目中所有模块的详情页导出pdf功能。本来开始后端接了这个活,前端只要传过去单号就好,可是做到最后一直实现不来,页面总是显示一半,于是,后端把活让给了我😢
还好,同组的其他伙伴项目中有用到过,给了我些帮助。
具体实现思路是:html2canvas 截屏页面快照,然后把照片插入到pdf页面内。
遇到的问题有:
1)
快照是空白的
首先页面DOM布局很重要,如果布局比较乱,很容易打印出空白页面。我们要知道html2canvas 截屏的元素是相对body元素定位的,所以我这里把要截屏的DOM元素copy了一份,放在body元素里。
let targetDom = document.querySelector('#pdfWrap');
let copyDom = targetDom.cloneNode(true);
copyDom.classList.add("copydom");
document.body.appendChild(copyDom);
但是这样也有问题,所以要从新缕清布局,尽量不要copy元素,因为cloneNode(true)无法copy echarts画出的图表~
2)pdf宽度很大,在a4纸打印不够
打印出来的PDF是等比例的缩放字体大小,如果宽度很宽,字体就会变得很小很小。这个时候就要和PM沟通协商,看看想怎么解决。
3)快照图片不显示
原因是跨域请求了图片资源,html2canvas 默认是不跨域的,所以在这里要设置下可跨域。
<img :src="item.path+'?'+new Date().getTime()" crossOrigin="anonymous"/>
html2canvas(copyDom, {
useCORS: true
4)快照截屏是当前可视窗口大小,没法滚动
我们页面比较长,有滚动条,所以会出现当前问题。设置当前要截屏的DOM元素的宽度和高度都为目标元素的滚动高度。
copyDom.style.height = targetDom.scrollHeight + "px";
copyDom.style.width = targetDom.scrollWidth + "px";
5)页面表格内容超出用省略号显示的解决办法
和PM沟通,需要把省略掉掉内容折行展示出来。html2canvas 的截图原则是所见即所得,所以页面是什么样子,打印出来是什么样子。因此,我需要在新的copy DOM元素下改变折行样式。(增加这行类名:export-mulit-line)
let recordDom = copyDom.getElementsByClassName('approval-records')[0];
let recordTableDom = recordDom.getElementsByClassName('data-table')[0];
recordTableDom.classList.add("export-mulit-line");
⚠️:这里涉及到了折行,页面高度会有所改变,所以要增加copyDOM元素的高度~(appendHeight即为变化的高度)
copyDom.style.height = targetDom.scrollHeight + appendHeight + "px";
总体实现代码:
// 判断是否多行
isMultiline(arr, num) {
return arr.some(e => {
return e.remark && e.remark.length > num;
getPdf(dom, title) {
this.loading = true;
let targetDom = document.querySelector('#pdfWrap');
let copyDom = targetDom.cloneNode(true);
copyDom.classList.add("copydom");
// 多行展示预算信息
let appendHeight = 0;//折行增加的高度
copyDom.style.height = targetDom.scrollHeight + appendHeight + "px";
copyDom.style.width = targetDom.scrollWidth + "px";
document.body.appendChild(copyDom);
utils.exportPDF(copyDom, this.orgInfo.orgName).then(v => {
this.loading = v;
utils.js
// 导出PDF
async exportPDF(copyDom, activityName) {
await html2canvas(copyDom, {
useCORS: true
.then(canvas => {
let contentWidth = canvas.width;
let contentHeight = canvas.height;
let pageHeight = contentWidth / 592.28 * 841.89;
let leftHeight = contentHeight;
let position = 0;
let imgWidth = 555.28;
let imgHeight = 555.28 / contentWidth * contentHeight;
console.log(contentHeight);
let pageData = canvas.toDataURL('image/jpeg', 1.0);
let PDF = new JsPDF('', 'pt', 'a4');
if (leftHeight < pageHeight) {
PDF.addImage(pageData, 'JPEG', 20, 0, imgWidth, imgHeight);
} else {
while (leftHeight > 0) {
PDF.addImage(pageData, 'JPEG', 20, position, imgWidth, imgHeight);
leftHeight -= pageHeight;
position -= 841.89;
if (leftHeight > 0) {
PDF.addPage();
PDF.save(activityName + '.pdf');