本文详解前端页面截屏的两种主流方案:基于html2canvas库的快速实现与原生Canvas手动绘制。针对html2canvas在移动端生成的图片模糊及跨域图片渲染问题,提供了通过放大Canvas物理尺寸并缩放显示的高清解决方案,以及使用Promise封装异步加载跨域图片的方法。对于高清晰度要求场景,深入解析了利用hidpi-canvas原理手动绘制DOM节点的技巧,确保在高清屏设备上输出清晰截图。
在前端开发中,"页面截屏"是常见需求,常用于生成海报或弹窗图片分享。由于浏览器未提供原生截图API,通常需借助Canvas技术导出图片以完成功能。
可行性方案
- 方案一:将DOM结构转换为Canvas,调用Canvas的toBlob或toDataURL方法,随后上传至七牛云或服务器。
- 方案二:使用第三方库html2canvas.js生成Canvas,无需修改现有DOM即可优雅地生成截图。
解决方案的选择
方案一需手动计算每个DOM元素的Computed Style,并精确计算元素在Canvas中的大小和位置等属性。
方案一难点
- 需放弃现有HTML页面,改用Canvas重新编写。
- 页面结构复杂时,使用Canvas重写不易重构。
- 开发者需具备一定的Canvas基础。
方案二:该项目在GitHub上Stars已超两万个,作者仍在积极维护。API简单,在现有项目中可开箱即用。
html2canvas
鉴于这是常见需求,社区已有成熟解决方案,建议首先尝试社区方案。
<div id="capture" style="padding: 10px; background: #f5da55">
<h4 style="color: #000; ">Hello world!</h4>
</div>
html2canvas(document.querySelector("#capture")).then(canvas => {
document.body.appendChild(canvas)
});
以上为官网实例用法。网页上会出现一个新的Canvas DOM节点。接下来只需将Canvas转换为图片,这里使用Canvas原生的toDataURL和toBlob方法上传至七牛云。
使用时需注意:若生成的画布中包含跨域图片,需配置allowTaint为true。
若使用原生Canvas实现,Canvas需等待所有跨域图片请求完成后方可绘制。有两种解决方案:
- 方案一:在HTML中预先写好img标签,src属性指定对应图片URL。缺点明显,会污染页面布局结构。
- 方案二:使用JavaScript,通过new Image()方式创建图片对象。设置src为对应图片URL,在onload回调中处理相关操作。优点:可行性最高,但存在回调地狱问题。我们使用Promise改写如下:
function asyncImage(url) {
const img = new Image();
img.src = url;
img.setAttribute('crossOrigin', 'anonymous');
return new Promise((resolve, reject) => {
img.onload = () => resolve(img);
img.onerror = reject;
});
}
好的,大功告成~是否可以直接交付需求了呢?开心提测后,在移动端测试时发现生成的图片非常模糊。这显然不行,明显降低了体验(测试不予通过orz)。
GitHub上有相应的解决方案 传送门 ,该回答也解决了多数人的问题。
基本原理:将Canvas宽高放大两倍,同时通过CSS将Canvas的style设置为1倍大小。
var shareContent = YourTargetElem;
var width = shareContent.offsetWidth;
var height = shareContent.offsetHeight;
var canvas = document.createElement("canvas");
var scale = 2 || window.devicePixelRatio ; //也可以使用设备像素比
canvas.width = width * scale;
canvas.height = height * scale;
canvas.getContext("2d").scale(scale, scale);
var opts = {
scale: scale,
canvas: canvas,
logging: true,
width: width,
height: height
};
html2canvas(shareContent, opts).then(function (canvas) {
var context = canvas.getContext('2d');
var img = Canvas2Image.convertToImage(canvas, canvas.width, canvas.height);
document.body.appendChild(img);
$(img).css({
"width": canvas.width / 2 + "px",
"height": canvas.height / 2 + "px",
})
});
原理已知,实际操作后图像清晰度确实提升。但问题仍未完全解决。
缩小虽提高了清晰度,但我们需要的图片是原始比例的大小。
最终多次尝试无果后,选择放弃使用框架。直接用原生Canvas手动绘制!
Canvas绘制
我们知道,在高清屏设备下,任何绘制Canvas中的图像、文字、线条、形状都可能出现模糊问题。可通过引入GitHub中的hidpi-canvas有效解决。
- 首先去GitHub下载hidpi-canvas.js文件:传送门;
- 在项目中引入hidpi-canvas.js文件;
- 调用getPixelRatio()函数,得到ratio值;
- 在drawImage()中,将width和height乘以ratio;
- 最终的Canvas导出为Blob,转换为文件对象上传至七牛云。
核心代码如下
function asyncImage(url) {
const img = new Image();
img.src = url;
img.setAttribute('crossOrigin', 'anonymous');
return new Promise((resolve, reject) => {
img.onload = () => resolve(img);
img.onerror = reject;
});
}
async function drawCanvas(){
var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
var ratio = getPixelRatio(context); // 关键代码
canvas.width = 300 * ratio; // 画布宽度
canvas.height = 300 * ratio; // 画布高度
var divWidth = 300 * ratio; // 用于内容居中
var divHeight = 300 * ratio; // 用于内容居中
const image = await asyncImage('picUrl')
const imgWidth = 550
const imgHeight = 300
context.drawImage(this, 50, 50, imgWidth * ratio, imgHeight * ratio)
// Some other code
const Blob = canvas.toBlob((Blob)=>{
//上传七牛云
});
}
最终生成的图片终于清晰了...只需根据DOM的offsetWidth等适配不同屏幕即可。
总结
如果对图片清晰度要求不高,或图片需求是生成缩略图的情况下,采用html2canvas是非常不错的选择。 否则,还是用Canvas绘制出的图片更清晰。
到此这篇关于JS如何实现页面截屏功能的文章就介绍到这了,更多相关JS页面截屏功能内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!