前言
网页截图导出不是一个十分高频的需要,但时不时的也会遇到。这里总结一下零碎的解决方案,而后从中抉择适合本人的。
截图导出能够看到是两个性能,第一步实现截图,第二步实现导出也就是下载能力。
截图实现
首先,咱们必须明确失常 javascript 是运行在浏览器里的,自身没有截图的能力。所以要想实现截图,必须通过其余曲折计划实现,废话少说,间接上论断。
前端计划 1 canvas
代表库 html2canvas
也有中文文档
实现原理:
html2canvas 是一个 HTML 渲染器,屏幕截图是基于 DOM,因而生成的图片并不一定 100% 统一,因为它没有制作理论的屏幕截图,而是依据页面上可用的信息构建屏幕截图。
文档介绍的比较清楚,canvas 只是去还原 dom 的展现成果。
依据实现原理,能够设想,实现老本还是比拟高的,须要解析 dom 和 css 款式,而且 css 款式不肯定能完满映射到 canvas,另外还会受限于 canvas 收到的一些限度,比方跨域资源问题。
前端计划 2 svg
代表库 dom-to-image
实现原理:
外围因素是 SVG 的一个个性,容许在 <foreignObject> 标签中蕴含任意的 HTML 内容。所以为了渲染该 dom 节点,须要如下步骤:
- 递归克隆原始 DOM 节点
- 计算节点和每个子节点的款式并将其复制到相应的克隆,并且要从新创立伪元素,因为它们当然不会以任何形式克隆
- 嵌入网页字体,链接所有 css 款式到 style 标签,利用到 clone 节点
- 嵌入图像
在 <img> 元素中嵌入图像 URL
背景 CSS 属性中应用的内嵌图像,以相似于字体的形式 - 将克隆的节点序列化为 XML
- 将 XML 包裹到 <foreignObject> 标签中,而后包裹到 SVG 中,而后使其成为数据 URL
- 创立一个以 SVG 作为源的 Image 元素,并将其出现在您也已创立的离屏画布上,而后从画布中读取内容
嗯,这就是 svg 形式实现了,和 canvas 形式一样,须要咱们解决 dom,css 和资源,然而后续的绘制渲染工作交给了浏览器,所以加重了很多工作量和代码量。
服务端计划
代表形式 puppeteer 实现
Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协定管制 Chromium 或 Chrome。这里具体就不介绍了,咱们只应用它的截图性能。
这个就是真正的截图能力了,官网有 demo。
思考到业务层的页面都须要用户拜访权限,所以正确的步骤应该是:
- 启动一个 node 服务,利用 puppeter 实现截图能力
- 客户端发动一个申请,携带 cookie
- 第一步启动的服务解决此申请,生成图片,地址返回给客户端
- 客户端拿到图片资源,进行下载即可
比照
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