DOM to Image 的原理解析
2022-01-25 18:56:29 # fontend

序言

在工作中遇到一个项目,需要当前视图可以导出为图片,目前前端的解决方案的话,就是要对当前 dom 进行截图处理。针对此解决方案的两个工具就是 html2canvas 和这里的 DOM to Image,这里就是将对 DOM to Image 这个包的使用方法和原理做一些说明。

dom-to-image

如何使用

1
2
3
4
5
6
7
8
9
10
11
12
// in ES6
import domtoimage from 'dom-to-image';
const node = document.getElementById('my-node');
domtoimage.toPng(node)
.then(function (dataUrl) {
var img = new Image();
img.src = dataUrl;
document.body.appendChild(img);
})
.catch(function (error) {
console.error('oops, something went wrong!', error);
});

实现原理

核心原理:该库使用 SVG 的一项功能,允许在 <foreignObject> 标记内包含任意 HTML 内容。

具体步骤:

  1. 递归克隆节点
    a. 复制节点或者子节点
    b. 复制节点的计算样式,伪类元素到克隆节点
    c. 复制用户输入区域内容,textarea 或者 input 区域的值
    d. 复制 svg 标签元素等
  2. 枚举获取网页的 @font-face,并通过 style 标签增加到克隆节点中
  3. 解析 image urls ,远程链接下载并通过 fileReader 转换成 dataurl
  4. 处理所有 css 行内规则并通过 <style> 标签添加
  5. 将所有 html 代码转换为 xml,并封装到 <foreignObject> 标签中 ,然后封装到 svg 中
  6. 转换为 png, jpge 则是基于 toSvg 的结果,通过 image load 读出图片信息放入 canvas 渲染图片,导出 dataUrl
  7. 转换 blob 则是根据 canvas 转的 blob 对象
  8. 转换为图片像素信息则是根据 canvas.getImageData

说明

  1. 如果无法兼容 svg 的阴影 drop-shadow, 导致导出的图片有问题
  2. dom-to-image 在chrome 上表现良好,性能最优,可能是因为 chrome 对 svg 支持的更好,ie 上不支持 svg 的 <foreignObject>, safari 上对此标签的支持具有更严格的安全模型,建议在safari 上使用时通过 toSvg 并在服务器上呈现。
  3. 跟 html2canvas 相比,这个库只有 770 行代码,更轻量。