从多个方面详解html2canvas.js下载

发布时间:2023-05-18

一、html2canvas截图下载

html2canvas 是一个能够实现将 HTML 界面转化为 Canvas 图像并导出的 JavaScript 库,使得前端开发人员能够很方便地把所见即所得的界面进行保存或导出、出图。我们可以通过以下代码引入 html2canvas

<script src="https://cdn.bootcdn.net/ajax/libs/html2canvas/1.0.0/html2canvas.min.js"></script>

在使用 html2canvas 进行截图之前,我们需要首先规划好需要截图的界面元素及导出方式。以下代码展示如何对页面进行截图并下载成 PNG 或 JPEG 格式:

html2canvas(document.body).then(function(canvas) {
    // 将 html2canvas 生成的 Canvas 对象转化为图片 url,传入浏览器默认下载函数即可实现下载图片的功能
    download(canvas.toDataURL(), 'canvas.png'); // 下载为 PNG 格式
    // download(canvas.toDataURL('image/jpeg'), 'canvas.jpg'); // 下载为 JPEG 格式
});
// 浏览器默认下载函数
function download(url, name) {
    var link = document.createElement('a');
    link.download = name;
    link.href = url;
    link.click();
}

代码执行后,我们即可获得一张下载下来的截图。

二、html2canvas官网

html2canvas 的官方网站为 https://html2canvas.hertzen.com/。通过访问该网站,我们可以找到 html2canvas 的相关文档和资源。以下是几个值得一提的资源:

  1. html2canvas GitHub 主页:https://github.com/niklasvh/html2canvas
    html2canvas 的 GitHub 代码仓库,包含了 html2canvas 的源码及其相关资源。
  2. html2canvas 在线示例:https://html2canvas.hertzen.com/examples
    html2canvas 提供了多个在线示例,可以通过这些示例了解 html2canvas 的具体应用。
  3. html2canvas 文档:https://html2canvas.hertzen.com/documentation
    html2canvas 的官方文档,包含了 html2canvas 的安装、基本使用、高级使用以及 API 等相关内容。

三、html2canvas源码解析

1、核心代码解析

以下为 html2canvas 的主要代码逻辑:

html2canvas(document.querySelector("#capture")).then(canvas => {
    document.body.appendChild(canvas);
});
function html2canvas(node) {
  // 初始化画布并返回一个 Promise 对象
  return new Promise(resolve => {
    // 创建一个 canvas 元素并赋予初始属性
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    // 将传入的节点进行转化为 Canvas
    renderNode(node, ctx).then(() => {
      resolve(canvas);
    });
  });
}
function renderNode(node, ctx) {
  // 创建包含当前节点的 Promise 对象
  return new Promise(resolve => {
    // 使用 window.getComputedStyle() 获取节点在渲染后的实际样式
    const style = window.getComputedStyle(node);
    // 获取节点的实际宽高
    const width = parseInt(style.getPropertyValue("width"));
    const height = parseInt(style.getPropertyValue("height"));
    // 将当前节点绘制到 Canvas 上
    ctx.drawImage(node, 0, 0, width, height);
    // 创建一个嵌套的 Promise 对象,来处理当前节点的子元素
    Promise.all(
      [...node.childNodes].map(node => renderNode(node, ctx))
    ).then(() => {
      resolve();
    });
  });
}

html2canvas 的核心逻辑在于将需要截图的节点转化为 Canvas 对象,经过多次 Promise 嵌套处理,最终返回一个包含有 Canvas 对象的 Promise 对象。通过 resolve() 可以实现异步代码的同步等待。

2、核心算法解析

html2canvas 的核心算法在于 Canvas 的绘制过程,具体包括以下几个步骤:

  1. 计算绘制的实际宽高
    首先通过 window.getComputedStyle() 获取节点在渲染后实际的样式,然后获取节点的实际宽高,为后续的绘制做准备。
  2. 绘制节点的背景及边框
    通过绘制一个填充为节点背景色的矩形,实现对节点背景的绘制;
    通过绘制多个边框,实现对节点边框的绘制。
  3. 绘制节点的子元素
    通过嵌套的 Promise 对象逐个处理子元素的绘制,最终实现对节点及其所有子元素的绘制。

3、html2canvas常见问题

1、跨域问题

默认情况下,html2canvas 会受到同源策略的限制,导致无法截图跨域的页面。我们可以通过配置 proxy 属性实现对跨域网页的截图。例如:

html2canvas(document.body, { 
  proxy: "https://html2canvas-proxy.xxxxx.com/proxy.php?url="
}).then(canvas => {
  document.body.appendChild(canvas);
});

proxy 属性需要对应一个接口来转发图片。具体实现方式可以参考 html2canvas-proxy 项目的源码。

2、低版本浏览器兼容问题

html2canvas 可能存在与 IE 浏览器及低版本浏览器之间的不兼容问题。为此,我们可以通过引入 html2canvas 的一些插件以及设置一些 CSS 属性来实现浏览器兼容,方法如下:

<!--[if lt IE 9]>
  <script src="//cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
  <script src="//cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->

2)设置 htmlbody 元素的高度及宽度为 100%,禁止滚动

html,body{
  width:100%;
  height:100%;
  overflow:hidden;
}

3)增加 SVG 规则

svg {
  overflow: hidden;
  margin: 0;
  padding: 0;
  width: 1em;
  height: 1em;
}

4)设置一些样式,如 opacity 属性等

四、HTML页面截图实战应用

html2canvas 的使用并不仅止于获取某个节点或整个页面的静态截图,其还可以在实际应用场景中发挥其大作用。以下是几个应用场景:

1、生成二维码

我们可以通过 html2canvas 的截图功能对生成的二维码进行截图保存,代码如下:

html2canvas(document.querySelector("#qr-code")).then(canvas => {
    document.body.appendChild(canvas);
    // 将 html2canvas 生成的 Canvas 对象转化为图片 url,传入浏览器默认下载函数即可实现下载图片的功能
    download(canvas.toDataURL(), 'qr-code.png'); // 下载为 PNG 格式
});

2、图片合成

通过 html2canvas 生成多张图片并进行合成,实现多帧动态效果的生成,代码如下:

const canvas_1 = document.createElement("canvas");
const canvas_2 = document.createElement("canvas");
html2canvas(document.querySelector(".block-1")).then(canvas => {
    canvas_1.width = canvas.width;
    canvas_1.height = canvas.height;
    const ctx = canvas_1.getContext("2d");
    // 将第一张图片绘制到画布上
    ctx.drawImage(canvas, 0, 0);
}).then(() => {
    html2canvas(document.querySelector(".block-2")).then(canvas => {
        canvas_2.width = canvas.width;
        canvas_2.height = canvas.height;
        const ctx = canvas_2.getContext("2d");
        // 将第二张图片绘制到画布上
        ctx.drawImage(canvas, 0, 0);
    });
}).then(() => {
    // 将两张画布合并成一张
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    canvas.width = canvas_1.width + canvas_2.width;
    canvas.height = canvas_1.height;
    ctx.drawImage(canvas_1, 0, 0);
    ctx.drawImage(canvas_2, canvas_1.width, 0);
    // 将 html2canvas 生成的 Canvas 对象转化为图片 url,传入浏览器默认下载函数即可实现下载图片的功能
    download(canvas.toDataURL(), 'merged.png'); // 下载为 PNG 格式
});
// 浏览器默认下载函数
function download(url, name) {
    var link = document.createElement('a');
    link.download = name;
    link.href = url;
    link.click();
}

通过以上实现方法,我们可以将多张静态图片合成成一张带有动态效果的图片。