使用 html2canvas 将 HTML 结构生成图片并复制到剪贴板

在 Web 开发中,有时我们需要将页面内容转换为图片,并且能够方便地复制到剪贴板。本文将介绍如何使用 html2canvas 实现这一功能,并展示如何在 Vue 项目中集成该功能。

背景需求

在现代 Web 应用中,常常需要将页面的某些部分截图,并进行保存或共享。例如:

  1. 用户界面反馈:用户可以截图并反馈界面问题。
  2. 数据展示:将数据图表、报告等内容生成图片,方便分享和保存。
  3. 内容存档:将动态生成的内容如发票、证书等保存为图片格式。

为了解决这些需求,我们可以使用 html2canvas 库,它能够将 HTML 元素及其样式渲染成 Canvas,并进一步转换为图片。

使用方法

我们以 Vue 项目为例,展示如何使用 html2canvas 生成图片,并一键复制到剪贴板。

首先,项目中安装 html2canvas

1
npm install html2canvas

接下来,我们实现一个简单的 Vue 组件,包含需要截图的内容和一个按钮用于触发截图操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<template>
<div id="app">
<div ref="content" style="padding: 20px; background: lightgray;">
这是需要截图并复制的内容。
</div>
<button @click="handleClick">复制到剪贴板</button>
</div>
</template>

<script>
import html2canvas from 'html2canvas';

export default {
methods: {
handleClick() {
html2canvas(this.$refs.content.$el).then((canvas) => {
canvas.toBlob(
async (blob) => {
console.log(blob);
try {
await navigator.clipboard.write([
new ClipboardItem({ [blob.type]: blob }),
]);
console.log("copy success");
} catch (error) {
console.log("copy fail");
}
},
"image/png",
1
);
});
},
},
};
</script>

扩展功能

上面的方法只能获取固定元素的图片,接下来我们使用右键菜单的方式实现自定义选择导出图片,话不多说上代码:

APP.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
<template>
<div class="home" @contextmenu.prevent="showContextMenu">
<MyComponent ref="MyComponent" />
<div class="box">
<p>本书覆盖 ES6 与上一个版本 ES5 的所有不同之处,对涉及的语法知识给予详细介绍,并给出大量简洁易懂的示例代码。</p>
<p>
本书为中级难度,适合已经掌握 ES5 的读者,用来了解这门语言的最新发展;也可当作参考手册,查寻新增的语法点。如果你是 JavaScript 语言的初学者,建议先学完《JavaScript 语言教程》,再来看本书。
</p>
<p>
全书已由电子工业出版社出版,2017年9月推出了第三版,书名为《ES6 标准入门》。纸版内容截止到出版时,网站内容一直在修订。
</p>
</div>
<!-- 右键菜单 -->
<div v-if="contextMenuVisible" :style="{ top: `${contextMenuY}px`, left: `${contextMenuX}px` }" class="context-menu">
<ul>
<li @click="copyToClipboard">复制为图片</li>
</ul>
</div>
</div>
</template>

<script>
import MyComponent from "@/components/MyComponent.vue";
import html2canvas from "html2canvas";

export default {
name: "Home",
components: { MyComponent },
data() {
return {
contextMenuVisible: false,
contextMenuX: 0,
contextMenuY: 0,
targetElement: null,
};
},
methods: {
copyElementToClipboard(element) {
html2canvas(element).then((canvas) => {
canvas.toBlob(
async (blob) => {
console.log(blob);
try {
await navigator.clipboard.write([
new ClipboardItem({ [blob.type]: blob }),
]);
console.log("copy success");
} catch (error) {
console.log("copy fail");
}
},
"image/png",
1
);
});
},
showContextMenu(event) {
this.contextMenuX = event.clientX;
this.contextMenuY = event.clientY;
this.targetElement = this.getClosestBodyChild(event.target);
this.contextMenuVisible = true;
document.addEventListener("click", this.hideContextMenu);
},
hideContextMenu() {
this.contextMenuVisible = false;
document.removeEventListener("click", this.hideContextMenu);
},
copyToClipboard() {
this.hideContextMenu();
this.copyElementToClipboard(this.targetElement);
},
getRootElement() {
return document.querySelector(".home");
},
getClosestBodyChild(element) {
while (
element.parentElement &&
element.parentElement !== this.getRootElement()
) {
element = element.parentElement;
}
return element.parentElement === this.getRootElement()
? element
: this.getRootElement();
},
},
};
</script>

MyComponent.vue

1
2
3
4
5
<template>
<div @contextmenu="$emit('contextmenu', $event)">
...
</div>
</template>
  1. 右键点击时子组件内 contextmenu 事件触发,并将事件对象传递给父组件,父组件监听到 contextmenu 事件,并通过 prevent 修饰符阻止默认的右键菜单出现,自定义右键菜单在鼠标右键点击处显示,通过 getClosestBodyChild 方法获取到离某个元素节点最近的节点—这样做是为了避免点击某个元素内的子元素造成生成图片不全
  2. 点击复制选项时触发 copyToClipboard 事件,使用 html2canvas 库使 html 节点转换为 canvas,再通过 toBlob 方法转化成 blob 数据,再通过 navigator.clipboard 的 API 将 blob 数据复制到剪切板(这个可能要在浏览器手动开启权限)
  3. 这样图片就复制好了,在其他地方粘贴即可使用

可能遇到的问题

  1. 动态内容内容缺失:可以设置延时器或使用promise等待数据获取
1
2
3
4
5
setTimeout(() => {
html2canvas(element).then((canvas) => {
// ...
});
}, 100); // 延迟 100 毫秒

未完待补充……


使用 html2canvas 将 HTML 结构生成图片并复制到剪贴板
http://47.95.158.220/2024/06/23/html2canvas/
作者
akkwei
发布于
2024年6月23日
许可协议