javascript实现网页截图导出方案

前言 网页截图导出不是一个非常高频的需求,但时不时的也会遇到。这里总结一下系统的解决方案,然后从中选择合适自己的。
截图导出可以看到是两个功能,第一步实现截图,第二步实现导出也就是下载能力。
截图实现 首先,我们必须明白正常javascript是运行在浏览器里的,本身没有截图的能力。所以要想实现截图,必须通过其他迂回方案实现,废话少说,直接上结论。
前端方案1 canvas
代表库html2canvas
也有中文文档
【javascript实现网页截图导出方案】实现原理:
html2canvas 是一个 HTML 渲染器,屏幕截图是基于 DOM,因此生成的图片并不一定 100% 一致,因为它没有制作实际的屏幕截图,而是根据页面上可用的信息构建屏幕截图。
文档介绍的比较清楚,canvas只是去还原dom的展示效果。
根据实现原理,可以想象,实现成本还是比较高的,需要解析dom和css样式,而且css样式不一定能完美映射到canvas,另外还会受限于canvas收到的一些限制,比如跨域资源问题。
前端方案2 svg
代表库dom-to-image
实现原理:
核心要素是SVG 的一个特性,允许在 标签中包含任意的 HTML 内容。所以为了渲染该dom节点,需要如下步骤:

  1. 递归克隆原始DOM节点
  2. 计算节点和每个子节点的样式并将其复制到相应的克隆,并且要重新创建伪元素,因为它们当然不会以任何方式克隆
  3. 嵌入网页字体,链接所有css样式到style标签,应用到clone节点
  4. 嵌入图像
    元素中嵌入图像 URL
    背景 CSS 属性中使用的内嵌图像,以类似于字体的方式
  5. 将克隆的节点序列化为 XML
  6. 将 XML 包裹到 标签中,然后包裹到 SVG 中,然后使其成为数据 URL
  7. 创建一个以 SVG 作为源的 Image 元素,并将其呈现在您也已创建的离屏画布上,然后从画布中读取内容
嗯,这就是svg方式实现了,和canvas方式一样,需要我们处理dom,css和资源,但是后续的绘制渲染工作交给了浏览器,所以减轻了很多工作量和代码量。
服务端方案
代表方式 puppeteer实现
Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。这里具体就不介绍了,我们只使用它的截图功能。
这个就是真正的截图能力了,官网有demo。
考虑到业务层的页面都需要用户访问权限,所以正确的步骤应该是:
  1. 启动一个node服务,利用puppeter实现截图能力
  2. 客户端发起一个请求,携带cookie
  3. 第一步启动的服务处理此请求,生成图片,地址返回给客户端
  4. 客户端拿到图片资源,进行下载即可
对比 html2canvas
优点 简单页面截图效果还可以,兼容性还好
缺点
  • 部分样式无法支持
  • 复杂页面,惨不忍睹。
  • cors可以解决跨域,但是实际应用还是问题百出
  • 实现非常复杂,难以改动
在我们项目几乎无法使用
dom-to-image
优点
  • 实现简单,可下载后自行改动源码
  • 还原度良好,尤其chrome支持非常好
缺点
  • safari支持不是很好,不过一些问题可以解决
基本能支持业务需求
后端截图
优点
  • 真实截图,终极方案,无兼容问题
缺点
  • 实现流程稍微繁琐
  • 需要考虑 用户权限认证问题
导出实现 导出也就是下载文件到本地
a标签
原理是通过a标签的download属性实现下载。
// 基本使用// 脚本触发 const download = (filename, url) => { let a = document.createElement('a'); a.style = 'display: none'; // 创建一个隐藏的a标签 a.download = filename; a.href = https://www.it610.com/article/url; document.body.appendChild(a); a.click(); // 触发a标签的click事件 document.body.removeChild(a); }

blob文件流对象
这个需要服务端支持,发起请求,服务端返回数据流,然后前端触发下载。
具体就不多说了,网上有很多文章。
这里推荐几个封装好的下载文件库
downloadjs
file-saver

    推荐阅读