介绍
html2Canvas生成图片展示,下载图片或下载为PDF格式文件。
html2Canvas使用方法
npm i html2canvas
npm i jspdf
import html2canvas from "html2canvas";
import JsPDF from "jspdf";
代码段
str:pdf标题; eles:需要下载的标签
const title = str;
const ele = document.querySelector(eles);
html2canvas(ele, {
allowTaint: true,
}).then((canvas) => {
//展示图片
const imgBlobData=canvas.toDataURL("image/png");
this.picUrl = window.URL.createObjectURL(imgBlobData)
//直接下载图片
const link = document.createElement('a'); // 创建一个超链接对象实例
const event = new MouseEvent('click'); // 创建一个鼠标事件的实例
link.download = 'Button.png'; // 设置要下载的图片的名称
link.href = canvas.toDataURL(); // 将图片的URL设置到超链接的href中
link.dispatchEvent(event); // 触发超链接的点击事件
//下载为PDF文件
const PDF = new JsPDF("p", "mm", "a4"); // A4纸,纵向
const ctx = canvas.getContext("2d");
const a4w = 190;
const a4h = 277; // A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
// eslint-disable-next-line no-mixed-operators
const imgHeight = Math.floor((a4h * canvas.width) / a4w); // 按A4显示比例换算一页图像的像素高度
let renderedHeight = 0;
while (renderedHeight < canvas.height) {
const 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
);
// 添加图像到页面,保留10mm边距
// eslint-disable-next-line no-mixed-operators
PDF.addImage(
page.toDataURL("image/jpeg", 1.0),
"JPEG",
10,
10,
a4w,
Math.min(a4h, (a4w * page.height) / page.width)
);
renderedHeight += imgHeight;
if (renderedHeight < canvas.height) {
PDF.addPage();
} // 如果后面还有内容,添加一个空页
}
PDF.save(`${title}.pdf`);
});
html2Canvas可能遇到的部分问题
1、图片跨域
解决方案:
-
设置配置项
allowTaint: false
canvas 的 CanvasRenderingContext2D 属于浏览器的对象,如果渲染过跨域资源,浏览器就认定 canvas 已经被污染了
Taint
:污点 -
设置配置项
useCORS: false
表示允许跨域资源共享,注意不能与 allowTaint 同时配置为 true
-
img 标签中添加
crossOrigin = "anonymous"
anonymous:如果使用这个值的话就会在请求 header 中带上 Origin 属性,但请求不会带上 cookie 和客户端 ssl 证书等其他的一些认证信息
-
图片服务器配置
Access-Control-Allow-Origin: *
重要的配置项,是跨域问题的根本源泉,需要后端配合
2、截图锯齿
解决方案:根据设备像素比进行缩放
// 设置放大倍数
const scale = window.devicePixelRatio;
3、截图不全
解决方案:截图之前将页面滚动到顶部
document.body.scrollTop = document.documentElement.scrollTop = 0;
const imgBlobData = await convertToImage(element);
4、对 css3 支持不好
html2canvas 暂不支持的 CSS 样式属性:
background-blend-mode、background-clip: text、box-decoration-break、repeating-linear-gradient()、font-variant-ligatures、mix-blend-mode、writing-mode、writing-mode、border-image、box-shadow、filter、zoom、transform
解决方案:
对于一些必要的样式,可以选择使用图片做兜底实现
box-shadow 可以参考 这个pr,修改源码解决,但是,实际效果也不是太理想……
5、svg 标签
问题原因:vue-lottie 动画库渲染的标签是 svg(也可能是你自己写的 svg 标签)
html2canvas 对于 svg 标签的支持也不尽人意,解决办法同样是用图片做兜底
在项目中,我们是用 svg 做动画,截图的时候把动画换成一张静态图,这样只要设置要静态图的样式,截图效果还是可以接受的