1. 原理介绍
该脚本遍历它所加载的页面的 DOM。它收集那里所有元素的信息,然后使用这些信息来构建页面的表示。换句话说,它实际上并没有截取页面的屏幕截图,而是根据它从 DOM 读取的属性构建它的表示。
结果,它只能正确渲染它理解的属性,这意味着有许多 CSS 属性不起作用。有关支持的 CSS 属性的完整列表,请查看 支持的功能页面。
2. 方案
这个库能将 HTML 转为 canvas,然后通过canvasAPI又能将 canvas 能转为图片,最后也可以通过a标签来实现图片的下载功能
那基本方案就是: html -> canvas -> image -> a[download]
- html2canvas.js:可将 htmldom 转为 canvas 元素。github传送门 ,官网传送门
- canvasAPI:toDataUrl() 可将 canvas 转为 base64 格式
- 创建 a[download] 标签触发 click 事件实现下载
3. 方案的具体实现代码
//点击生成图片
generateImage() {
if(this.state.productData.length>=100){
this.over100=true;
this.isOver100Refresh=true;
over100_list=this.state.productData
this.state.productData=over100_list.slice(0,100)
return
}
this.notMyTitle = false;
this.notMyFooter = false;
this.isLoadingBottom = false;
document.querySelector('#area').scrollTop = 0;
document.querySelector('.prodListH5').scrollLeft = 0;
this.$refs.prodListH5Title.classList.remove('xiDing'); //生成图片出错处理
document.getElementById('area').style.height = 'auto';
var rect = document.getElementById('appArea').getBoundingClientRect(); // 关键代码
let height =
rect.height +
(158 * ((this.state.trList.width - 24) / 321) + 80 > 300 ? 158 * ((this.state.trList.width - 24) / 321) + 80 : 300); // 加上底部新增图片高度(40是margin值),避免截取不全
let width = rect.width;
let userAgent = navigator.userAgent;
// 苹果手机
if (userAgent.includes('iPhone') || userAgent.includes('iPad')) {
var scale = 3000000 / height / width > 2 ? 2 : 1;
} else {
//取的谷歌浏览器
var scale = 14000 / height > 2 ? 2 : 1;
}
html2canvas(document.getElementById('appArea'), {
// scrollY: 2 * rect.top, // 关键代码
scale, //图像太长处理
scrollY: rect.top,
height,
width: rect.width,
}).then((canvas) => {
canvas.toBlob((blob) => {
// this.imgUrl = URL.createObjectURL(blob)
// var aImg = document.createElement("a");
this.imgUrl = canvas.toDataURL('image/jpeg');
var img = document.createElement('img');
img.setAttribute('src', this.imgUrl);
img.className = 'imgItem';
img.style.width = '100vw';
img.style.height = 'auto';
document.querySelector('.canvasImg').appendChild(img);
document.querySelector('.imgBox').onclick = () => {
document.getElementById('area').style.height = '88vh';
document.querySelector('.canvasImg').removeChild(img);
document.querySelector('.imgBox').style.display = 'none';
document.querySelector('.saveBtn').style.display = 'block';
this.notMyTitle = true;
this.notMyFooter = true;
this.isLoadingBottom = true;
};
document.querySelector('.imgBox').style.display = 'block';
document.querySelector('.saveBtn').style.display = 'none';
}, 'image/png');
});
},
4. 避坑指南
(1) 图片模糊
因为开发的项目过程中,有滚动效果,截取的图片不仅仅是可视窗口的宽高,当数据过多,图片过长等情况,会出现图片模糊的情况,可以通过设置 scale 配置项来解决
html2canvas(document.getElementById('appArea'), {
// scrollY: 2 * rect.top, // 关键代码
scale, //图像太长处理
scrollY: rect.top,
height,
width: rect.width,
}).then((canvas)=>{...//这里已经绘制完成canvas,进行转base64图片等操作})
至于scale的取值,用于渲染的比例。默认为浏览器设备像素比
/** * 根据window.devicePixelRatio获取像素比 */
function DPR() {
if (window.devicePixelRatio && window.devicePixelRatio > 1) {
return window.devicePixelRatio;
}
return 1;
}
(2) 部分ios端出现文字重叠情况
当页面中有内容文字自动换行,且文字设置了text-align:center的情况下,会出现文字内容的高度不变,但文字会重叠到一行上,,粗略解决方法是设置text-align:left下,能解决这个问题,
顺便提一下的是,之前尝试用v-html的方式去渲染,手动去添加换行符,文字处理还是保持text-align:center的处理方式,但并没有成功
问题效果如图所示:
(3) 截屏出来的图片左右区域出现空白
问题出现的情况:当页面向下滚动或者向右滚动了一定距离的时候,会出现截取不全而出现空白的情况
解决的方案:
1.在htmldom转为canvas之前,将页面滚动到scrollTop scrollLeft为0的时候可以解决
(4) 图片底部新增的名片没显示出来,有高度(占了位置)但是空白
问题出现的原因:canvas
元素达到浏览器的canvas
大小限制,窗口限制因浏览器、操作系统和系统硬件而异。具体值
5. 番外
(1)parseInt注意事项
在使用 parseInt
时,尽量都指定一个 radix原因
/** * 将传入值转为整数 */
function parseValue(value) {
return parseInt(value, 10);
};
语法:
parseInt(string, radix);
-
string
要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用
ToString
抽象操作)。字符串开头的空白符将会被忽略。
-
radix 可选
从
2
到36
,表示字符串的基数。例如指定 16 表示被解析值是十六进制数。请注意,10不是默认值!
从给定的字符串中解析出的一个整数。
或者 NaN
,当
radix
小于2
或大于36
,或- 第一个非空格字符不能转换为数字。
parseInt('123', 5) // 将'123'看作5进制数,返回十进制数38 => 1*5^2 + 2*5^1 + 3*5^0 = 38