点击上方 程序员成长指北,关注公众号

回复 1,加入高级 Node 交流群

导语 | 本文将介绍在前端开发中页面截图的两种方式,包括对其实现原理和使用方式进行详细阐述,希望能为更多前端开发者提供一些经验和帮助。

一、 背景

页面截图功能在前端开发中,特别是营销场景相关的需求中, 是比较常见的。比如截屏分享,相对于普通的链接分享,截屏分享具有更丰富的展示、更多的信息承载等优势。最近在需求开发中遇到了相关的功能,所以调研了相关的实现和原理。

二、相关技术

前端要实现页面截图的功能,现在比较常见的方式是使用开源的截图 npm 库,一般使用比较多的 npm 库有以下两个:

以上两种常见的 npm 库,对应着两种常见的实现原理。实现前端截图,一般是使用图形 API 重新绘制页面生成图片,基本就是 SVG(dom-to-image)和 Canvas(html2canvas)两种实现方案,两种方案目标相同,即把 DOM 转为图片,下面我们来分别看看这两类方案。

三、 dom-to-image

dom-to-image 库主要使用的是 SVG 实现方式,简单来说就是先把 DOM 转换为 SVG 然后再把 SVG 转换为图片。

(一)使用方式

首先,我们先来简单了解一下 dom-to-image 提供的核心 api,有如下一些方法:

  • toSvg (dom 转 svg)

  • toPng (dom 转 png)

  • toJpeg (dom 转 jpg)

  • toBlob (dom 转二进制格式)

  • toPixelData (dom 转原始像素值)

如需要生成一张 png 的页面截图,实现代码如下:

  1. import domtoimage from "domtoimage"
  2. const node = document.getElementById('node');
  3. domtoimage.toPng(node,options).then((dataUrl) => {
  4. const img = new Image();
  5. img.src = dataUrl;
  6. document.body.appendChild(img);
  7. })

toPng 方法可传入两个参数 node 和 options。

node 为要生成截图的 dom 节点;options 为支持的属性配置,具体如下:filter,backgroundColor,width,height,style,quality,imagePlaceholder,cacheBust。

(二)原理分析

dom to image 的源码代码不是很多,总共不到千行,下面就拿 toPng 方法做一下简单的源码解析,分析一下其实现原理,简单流程如下:

2种方式快速实现前端截图 - 图1

整体实现过程用到了几个函数:

  • toPng(调用 draw,实现 canvas=>png )

  • Draw(调用 toSvg,实现 dom=>canvas)

  • toSvg(调用 cloneNode 和 makeSvgDataUri,实现 dom=>svg)

  • cloneNode(克隆处理 dom 和 css)

  • makeSvgDataUri(实现 dom=>svg data:url)

  • toPng

toPng 函数比较简单,通过调用 draw 方法获取转换后的 canvas,利用 toDataURL 转化为图片并返回。

  1. function toPng(node, options) {
  2. return draw(node, options || {})
  3. .then((canvas) => canvas.toDataURL());
  4. }
  • draw

draw 函数首先调用 toSvg 方法获得 dom 转化后的 svg,然后将获取的 url 形式的 svg 处理成图片,并新建 canvas 节点,然后借助 drawImage() 方法将生成的图片放在 canvas 画布上。

  1. function draw(domNode, options) {
  2. return toSvg(domNode, options)
  3. .then(util.makeImage)
  4. .then(util.delay(100))
  5. .then((image) => {
  6. const canvas = newCanvas(domNode);
  7. canvas.getContext("2d").drawImage(image, 0, 0);
  8. return canvas;
  9. });
  10. function newCanvas(domNode) {
  11. const canvas = document.createElement("canvas");
  12. canvas.width = options.width || util.width(domNode);
  13. canvas.height = options.height || util.height(domNode);
  14. if (options.bgcolor) {
  15. const ctx = canvas.getContext("2d");
  16. ctx.fillStyle = options.bgcolor;
  17. ctx.fillRect(0, 0, canvas.width, canvas.height);
  18. }
  19. return canvas;
  20. }
  21. }
  • toSvg

  • toSvg 函数实现从 dom 到 svg 的处理,大概步骤如下:

  • 递归去克隆 dom 节点(调用 cloneNode 函数)

  • 处理字体,获取所有样式,找到所有的 @font-face 和内联资源,解析并下载对应的资源,将资源转为 dataUrl 给 src 使用。把上面处理完的 css rules 放入