通过前端的手段实现截图功能,主要分为两种情况:
- 对浏览器网页页面的截图。
- 仅对canvas画布的截图,比如可视化图表、webGL等。
对于第一种情况,将浏览器网页页面截图,在前端无权限控制浏览器相关接口的情况下,要实现网页的截图,主要思路还是靠页面dom转化成canvas或者svg图片来解决。有两个比较著名的库html2canvas、dom-to-image便提供了这种功能,当然,这里面有一些限制和坑。
实际应用上,在pc端这种需求不算多,而且浏览器本身就提供了网页的截图功能,并不需要前端程序来操控。感兴趣的可以查看这篇文章了解详情,便不再赘述。
对于第二种情况,将canvas
画布截图,这种需求主要集中在保存图表、可视化界面等,不过实现起来十分简便,因为canvas
它本身就有保存为图片的功能,它有两个API可以用来导出图片,分别是 toDataURL
和 toBlob
。
toDataURL
方法是将整个画布转换成base64格式的url地址,toBlob
方法是创造Blob对象,默认图片类型是image/png。
注:
canvas
的两个APItoDataURL()
和toBlob()
都受到同源策略的限制而无法跨域,也就是说如果canvas的画面来源是跨域请求,则调用该api会报跨域错误,常见解决方式是让后端设置允许跨域,前端将crossOrigin 属性值设置为anonymous 。
以three.js
做3D可视化界面为例,我们需要把3d模型截图保存下来。因为我们的模型是渲染在canvas画布上,所以可以直接通过toBlob
方法来截图保存,我们将这些封装成一个截图方法:
// 将截图方法封装成方法,传递两个参数:
// canvas:指定截图的canvas元素
// fileName:下载的文件名
const screenshotCanvas = (canvas, fileName) => {
// 验证canvas元素
if (
!canvas ||
canvas.nodeType !== Node.ELEMENT_NODE ||
canvas.nodeName.toLowerCase() !== 'canvas'
) {
throw new Error('请传入要截图的canvas元素')
}
try {
canvas.toBlob((blob) => {
// 创建a元素来实现下载
const a = document.createElement('a')
a.style.display = 'none'
document.body.appendChild(a)
a.href = window.URL.createObjectURL(blob)
// 下载的文件名
a.download = fileName || `screenshot-${canvas.width}x${canvas.height}.png`
a.click()
// 触发下载后,移除元素
a.remove()
})
} catch (e) {
console.log(e)
}
}
复制代码
这样就可以将canvas画布内容截图保存下来了。
注:出于性能和兼容性的原因,默认情况下浏览器在绘制到WebGL画布的绘制缓冲区后会清除它,所以在截图之前一定要渲染一次,否则截图不出来。