当我们使用浏览器(或“客户端”)进行屏幕截图开发时,在所选场景之间需要权衡,并且没有可以解决每种情况的完美解决方案。让我们看一下可用于屏幕截图的三种不同形式,以及如何通过将它们发送到服务器或让用户下载图像来使用它们。
屏幕截图是JavaScript应用程序中有价值且重要的部分。像谷歌这样的公司使用它们来获取用户的反馈,像Bugherd这样的产品使用屏幕截图作为其产品的核心部分,并且特别适合数据导入(如图表)。
要求用户截取他们正在观看的内容的屏幕截图可能会给用户带来很多麻烦。首先,他们需要知道快捷键(MacOS和Windows是不同的)。
然后他们需要知道下一步该怎么做。例如,他们可以将其上传到Dropbox等地方或通过短信发送给您。大多数用户可能不知道如何调整或优化屏幕截图的质量。如果您存储自己的屏幕截图,请确保它们占用尽可能少的空间,以确保您消耗尽可能少的空间。
接下来,介绍了三种为用户手动捕获屏幕截图的方法。
1. 使用 HTML2canvas 进行客户端截图
2011年 Niklas von Hertzen 在 Stackoverflow 上回答了一个问题,他说页面 DOM 可以加载到 HTML Canvas 中并用于生成屏幕截图。然后,他公开了代码并更新了答案HTML2Canvas。后来的调查显示,谷歌使用非常相似的技术手动生成屏幕截图,以提供用户反馈作为证据,并且对于小型产品来说足够强大。
如何使用 HTML2Canvas
这很简单浏览器禁用了javascript,当你想生成一个截图时,你所要做的就是获取DOM(页面的HTML)并将DOM传递到HTML画布中。在个别限制下,canvas 元素可以生成数据 URI(作为 base64 字符串)。下面的示例生成屏幕截图,并将其作为窗口中的图像打开。
const screenshotTarget = document.body;
html2canvas(screenshotTarget).then((canvas) => {
const base64image = canvas.toDataURL("image/png");
window.location.href = base64image;
});
使用画布的优缺点
快。您无需等待任何外部服务,这一切都在客户端上完成。虽然HTML2canvas不是每晚更新的,但它通常每隔几个月定期更新和修补。社区强大而活跃,在那里打开了 40 多个拉取请求,记录了 600 多个问题(截至 2020 年 7 月)。在Stack Overflow中也有很多问题(和答案!)。)。良好的浏览器兼容性,HTML2canvas已有9年的历史,并保持了出色的浏览器兼容性。
弊
不支持影子 DOM(或 Web 组件)。有一个开放的拉取请求来减少支持,维护者似乎急于合并分支。
跨域限制。当您降低画布以包含请求元素(如图像或 CSS 样式)时,由于跨域策略,这些元素将被拒绝。
并非所有 CSS 属性都受支持。该文档明确指出“HTML2canvas不会提供完整的CSS功能”。
2. 使用getDisplayMedia生成屏幕截图
在HTML2canvas发布的同时,Web应该支持原生视频通话的想法也越来越受欢迎。2011年,谷歌发布了实时视频和音频平台Hangouts。为了支持环聊,谷歌提出并实现了实时通信(RTC)的想法,后来演变为WebRTC。WebRTC已成为所有现代浏览器的标准,它是Web上实时视频,音频和数据传输的基础设施。
getDisplayMedia是WebRTC中用于屏幕共享的API。您可以从视频中获取静态图像,就像屏幕共享一样,但本质上是屏幕截图。让我们看一个基本的例子:
const capture = async () => {
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
const video = document.createElement("video");
try {
const captureStream = await navigator.mediaDevices.getDisplayMedia();
video.srcObject = captureStream;
context.drawImage(video, 0, 0, window.width, window.height);
const frame = canvas.toDataURL("image/png");
captureStream.getTracks().forEach(track => track.stop());
window.location.href = frame;
} catch (err) {
console.error("Error: " + err);
}
};
capture();
虽然上面的例子没有第一个那么简单,但还是很容易理解的。首先,在视频内存中创建画布和视频元素,然后使用 getDisplayMedia API 请求访问用户的桌面或选项卡。用户授权后,屏幕流将设置为视频元素,然后在画布上草绘。以与 HTML2canvas 示例中相同的方式从画布导入图像。
getDisplayMedia API 的优缺点
良好的现代浏览器支持 - 它是一个本机API,即内置在浏览器中,这意味着它不需要依赖任何第三方脚本和代码。
可扩展性 - 如您所见,使用相同的API,将来可以轻松减少视频录制的功能。
桌面 ||选项卡 - getDisplayMedia API 可以记录其他桌面或浏览器窗口,这使其功能强大,并且可以截取应用外部内容的屏幕截图。
弊
权限 - 需要获取用户的权限。由于它取决于浏览器,因此权限对话框可能看起来不同,这有时会有点令人困惑。
慢 - 由于您需要获取权限,因此用户需要一些时间来单击并了解正在发生的事情。如果用户需要立即获取屏幕截图,则此小型 UI 交互在捕获时间敏感内容时会有一些延迟。
3. 截图服务屏幕截图
服务正变得越来越流行,提供了一种将屏幕截图功能集成到应用程序中的简单方法。但是,它不是在客户端执行的浏览器禁用了javascript,需要url2png,Stillio和Urlbox等服务,这也意味着您不必担心使用什么基础设施来获取屏幕截图。
尽管每个服务可能实现不同的方法,但思路大致相同。将 URL(以及自定义参数:大小、格式、质量)发送到外部服务,并等待返回响应数据。这些通常使用前端服务来处理,所以让我们看看使用 url2png 和 Nodejs 和 Express 的实现。
const url2png = require('url2png')('API_KEY', 'PRIVATE_KEY');
const fs = require('fs');
app.get('/screenshot', (req, res) => {
url2png.readURL(req.query.url, {}).pipe(fs.createWriteStream('screenshot.png'));
res.json({success: true})
});
在上面的例子中,我们可以使用以下方法来请求:
/screenshot?url=http://google.com.au
实际上,我们正在使用 url2png 库来生成屏幕截图。屏幕截图将保存在您的本地文件系统中,或者您可以通过套接字返回它们。
截图服务的优缺点
后处理——可提供更多的后处理功能,如灵活设置图像格式、大小、质量等;
健壮性 - 可供许多用户使用,并且易于处理大量请求。您不需要维护与屏幕截图过程相关的基础架构,如果您满意,PhantomJS和SauceLabs服务等项目是一个良好的开端。
弊
无状态 - 屏幕截图可能不是用户听到的内容,例如,如果用户已经在页面上进行了一些交互,或者页面需要登录,则屏幕截图服务可能难以截取同一页面的屏幕截图。
成本 - 在上述三个选项中,这是唯一需要成本的选项。虽然它非常实惠,但如果您要处理大量的屏幕截图需求,它会很昂贵。
时间
- 屏幕截图服务可能需要几分钟才能生成并返回图像。
总结一下
如果您将屏幕截图作为一项重要功能集成到您的应用程序中,则需要仔细查看每种解决方案的优缺点。
使用客户端解决方案,如html2canvas或getDisplayMedia API,意味着你不需要管理任何服务器端设施,并且可以快速生成屏幕截图。
如果您需要恢复用户在像素级别听到的内容,并且不介意频繁的授权弹出窗口,那么getDisplayMedia API是一个好的开始。
如果您想在没有其他服务依赖项的情况下快速获得不太准确的屏幕截图,HTML2canvas 可能是更好的选择。
是浏览器根据系统的当前配置和加载的页面 JavaScript 提供的一系列对象
如窗口对象、冲洗对象、历史对象等
文档对象模型 (DOM)。
DOM-DocumentObjectModeljavascript内置对象有哪些,W3C International的一组Web标准。它以树结构表示文档(HTML、XML 等),定义用于遍历、检查和更改每个节点的属性和技术。
DOM:文档对象模型
能做什么?
1. 获取元素
2. 删除元素
3. 创建元素
4. 在页面顶部添加元素
5.将元素绑定到一些风暴中
6. 获取元素的属性
7. 为元素添加一些 CSS 样式
DOM 的核心对象是文档对象
文档对象是浏览器外部对象的对象,它存储专门用于操作元素的各种技术
记录通用属性
getElementById()
按 id 获取元素
getElementsByTagName()
获取标签
通过元素名称,你得到的是一组标签
getElementsByName()标签
是通过标签的名称属性值获得的,结果也是一组元素
getElementsByClassName(“sp”)
获取类应用值为 sp 的所有标记
querySelector()
通过选择器获取标签,您将获得单个标签
querySelectorAll()
获取标签
通过选择器javascript内置对象有哪些,获取所有符合条件的标签
createElement(“Tag Name”
)。
创建新标签
appendChild()
向标记添加子元素
firstElementChild元素
的第一个子元素
上一个元素子元素
的最后一个子元素
删除子()
删除的是子元素
删除()
清除元素的所有子元素,包括元素本身