在前端开发中,偶尔会遇到导出页面为图片(或海报)或者PDF这种常见需求,大多数是直接获取DOM,然后通过htm2canvas库(导出pdf的话还需要加上pdf.js库)导出,但是大部分直接导出样式总会出点问题(比如行高不对,样式错乱等),另外想在导出的页面中加一些图片或者其他元素,有些不方便。所以我这边思路是重新开一个导出组件,用来放要导出的元素,以及要额外放的一些内容(也就是在保留原有页面的基础上,基于业务数据新写一个...);下面使用htm2canvas导出图片,使用pdf.js导出为pdf
# 效果展示:需要导出的页面
# 效果展示:导出效果预览
# 基于以下两个库
import html2canvas from 'html2canvas';
import JsPDF from 'jspdf';
1
2
2
# 以下函数共三个功能,复制图片、导出为图片、导出为pdf(可分页)
其中downloadImgAndPdf函数的入参是1、2、3,分别代表复制图片、下载图片、下载pdf
downloadImgAndPdf(val) {
let excludeSelectors = ['.screenBtn', '.copyBtn', '.copyBtnuser', '.copycodebtn'];// 需要排除的元素选择器,这些元素不会出现在导出的图片中
const divIds = ['scrollBox'];// 需要截图的元素id
const pdf = new JsPDF('p', 'mm', 'a4');// A4纸,纵向
const captureScrollableContent = async (divId) => {
const originalDiv = document.getElementById(divId);
// 创建克隆节点
const clonedDiv = originalDiv.cloneNode(true);
document.body.appendChild(clonedDiv);
// 设置克隆节点样式
clonedDiv.style.position = 'absolute';
clonedDiv.style.left = '-9999px';
clonedDiv.style.height = 'auto';
clonedDiv.style.width = '840px'; // 设置固定宽度
clonedDiv.style.overflow = 'visible';
// 隐藏克隆节点中需要排除的元素
excludeSelectors.forEach(selector => {
clonedDiv.querySelectorAll(selector).forEach(el => {
el.style.display = 'none';
});
});
try {
const canvas = await html2canvas(clonedDiv, {
allowTaint: false,
taintTest: false,
logging: false,
useCORS: true,
width: 840,
scale: 2,
});
return canvas;
} finally {
// 移除克隆节点
document.body.removeChild(clonedDiv);
}
};
const promises = divIds.map(captureScrollableContent);
Promise.all(promises).then(canvases => {
canvases.forEach((canvas, index) => {
if (val === '1') {//val为1是复制图片
// 生成图片URL
const imageData = canvas.toDataURL("image/png");
// 创建一个隐藏的a标签用于下载
// 将 base64 转换为 Blob 对象
fetch(imageData)
.then(res => res.blob())
.then(blob => {
// 创建一个新的剪贴板项目
const item = new ClipboardItem({ "image/png": blob });
// 使用 Clipboard API 复制到剪贴板
navigator.clipboard.write([item]).then(() => {
this.$Message.success("复制成功")
}).catch(err => {
this.$Message.error("复制失败")
});
});
} else if (val === '2') { //val为2是下载图片
// 生成图片URL
const imageData = canvas.toDataURL("image/png");
// 创建一个隐藏的a标签用于下载
const link = document.createElement('a');
link.href = imageData;
link.download = `image_${index + 1}.png`; // 设置下载的文件名
// 模拟点击下载
link.click();
} else { //val为3是下载pdf
// 生成图片URL
const imageData = canvas.toDataURL("image/png");
// 创建一个隐藏的a标签用于下载
const link = document.createElement('a');
link.href = imageData;
link.download = `image_${index + 1}.png`; // 设置下载的文件名
if (index > 0) {
pdf.addPage();
}
this.addCanvasToPdf(pdf, canvas);
pdf.save('人工智能平台.pdf');
}
});
}).catch(error => {
console.error('Error generating images:', error);
});
},
addCanvasToPdf(pdf, canvas) {//添加canvas到pdf
var ctx = canvas.getContext('2d');// 获取画布的2D上下文
var a4w = 190; var a4h = 277; // A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
var imgHeight = Math.floor(a4h * canvas.width / a4w); // 按A4显示比例换算一页图像的像素高度
var renderedHeight = 0;
while (renderedHeight < canvas.height) {
var page = document.createElement('canvas');
page.width = canvas.width;
page.height = Math.min(imgHeight, canvas.height - renderedHeight);// 可能内容不足一页
// 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0);
pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width)); // 添加图像到页面,保留10mm边距
renderedHeight += imgHeight;
if (renderedHeight < canvas.height) {
pdf.addPage();// 如果后面还有内容,添加一个空页
}
}
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106