乐趣区

关于html2canvas:javascript实现网页截图导出方案

前言

网页截图导出不是一个十分高频的需要,但时不时的也会遇到。这里总结一下零碎的解决方案,而后从中抉择适合本人的。

截图导出能够看到是两个性能,第一步实现截图,第二步实现导出也就是下载能力。

截图实现

首先,咱们必须明确失常 javascript 是运行在浏览器里的,自身没有截图的能力。所以要想实现截图,必须通过其余曲折计划实现,废话少说,间接上论断。

前端计划 1 canvas

代表库 html2canvas
也有中文文档

实现原理:
html2canvas 是一个 HTML 渲染器,屏幕截图是基于 DOM,因而生成的图片并不一定 100% 统一,因为它没有制作理论的屏幕截图,而是依据页面上可用的信息构建屏幕截图。
文档介绍的比较清楚,canvas 只是去还原 dom 的展现成果。

依据实现原理,能够设想,实现老本还是比拟高的,须要解析 dom 和 css 款式,而且 css 款式不肯定能完满映射到 canvas,另外还会受限于 canvas 收到的一些限度,比方跨域资源问题。

前端计划 2 svg

代表库 dom-to-image

实现原理:
外围因素是 SVG 的一个个性,容许在 <foreignObject> 标签中蕴含任意的 HTML 内容。所以为了渲染该 dom 节点,须要如下步骤:

  1. 递归克隆原始 DOM 节点
  2. 计算节点和每个子节点的款式并将其复制到相应的克隆,并且要从新创立伪元素,因为它们当然不会以任何形式克隆
  3. 嵌入网页字体,链接所有 css 款式到 style 标签,利用到 clone 节点
  4. 嵌入图像
    在 <img> 元素中嵌入图像 URL
    背景 CSS 属性中应用的内嵌图像,以相似于字体的形式
  5. 将克隆的节点序列化为 XML
  6. 将 XML 包裹到 <foreignObject> 标签中,而后包裹到 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 属性实现下载。

// 根本应用
<a href="/images/xxxxx.jpg" download="filename">

// 脚本触发
const download = (filename, url) => {let a = document.createElement('a'); 
    a.style = 'display: none'; // 创立一个暗藏的 a 标签
    a.download = filename;
    a.href = url;
    document.body.appendChild(a);
    a.click(); // 触发 a 标签的 click 事件
    document.body.removeChild(a);
}

blob 文件流对象

这个须要服务端反对,发动申请,服务端返回数据流,而后前端触发下载。
具体就不多说了,网上有很多文章。

这里举荐几个封装好的下载文件库
downloadjs
file-saver

退出移动版