2种方式!带你快速实现前端截图

共 13705字,需浏览 28分钟

 ·

2022-03-06 10:02


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


一、 背景


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


二、相关技术


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


  • dom-to-image: 

    https://github.com/tsayen/dom-to-image


  • html2canvas: 

    https://github.com/niklasvh/html2canvas


以上两种常见的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的页面截图,实现代码如下:


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


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


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



(二)原理分析


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



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


  • 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转化为图片并返回。


function toPng(node, options) {  return draw(node, options || {})    .then((canvas) => canvas.toDataURL());}


  • draw


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


function draw(domNode, options) {  return toSvg(domNode, options)  // 拿到的svg是image data URL, 进一步创建svg图片    .then(util.makeImage)    .then(util.delay(100))    .then((image) => {      // 创建canvas,在画布上绘制图像并返回      const canvas = newCanvas(domNode);      canvas.getContext("2d").drawImage(image, 0, 0);      return canvas;    });  // 新建canvas节点,设置一些样式的options参数  function newCanvas(domNode) {    const canvas = document.createElement("canvas");    canvas.width = options.width || util.width(domNode);    canvas.height = options.height || util.height(domNode);    if (options.bgcolor) {      const ctx = canvas.getContext("2d");      ctx.fillStyle = options.bgcolor;      ctx.fillRect(0, 0, canvas.width, canvas.height);    }    return canvas;  }}


  • toSvg


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


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


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