轻松搞定网页截图,html2canvas入门教程
点赞 + 关注 + 收藏 = 学会了 html2canvas 是一个纯前端的 JavaScript 库,能直接在浏览器里把 HTML 元素 “拍” 成 Canvas 图片。不用麻烦后端接口,就能实现网页截图、生成分享海报、保存页面快照等需求。 html2canvas 支持两种常见的安装方式,根据你的项目环境选就行: 如果你的项目用了 Webpack、Vite 等构建工具,直接用包管理器安装: 本文使用 Vite 创建 Vue3 项目,通过 Vue3 的语法来讲解。在其他框架使用 html2canvas 用法也是差不多的。 如果是简单的 HTML 项目,直接在页面里引入 CDN 链接: 先看一个最简单的例子:点击按钮,把指定的 这段代码看似简单,但第一个坑也出现了。 此时如果在“截图区”加多一个 解决方法很简单,不使用浏览器默认样式,给所有标签都加上指定样式。 html2canvas 提供了很多配置项,能帮你解决各种场景问题,这里列几个最常用的: 如果你要截的元素包含图片,而且这张图片和你的网站存在跨域情况,大概率会出现图片出空白的情况。 要解决这个问题需要2步操作。 如果想更稳妥一点,还可以给图片标签加 https://iili.io 这个图床是允许跨域的,所以我们直接在 html2canvas 里配置 生成 Canvas 后,通常需要把它转成图片文件让用户下载,这里用 html2canvas 虽然好用,但坑也不少。 前面已经提到了,如果截图里有跨域图片(比如图床的图),默认会显示空白。原因是浏览器的同源策略限制,html2canvas 无法直接读取跨域图片的像素。 解决方法: 部分 CSS 属性(如 html2canvas 是通过解析 DOM 和 CSS 手动绘制 Canvas 的,不是所有 CSS 都支持。 解决方法: 用了自定义字体(如 @font-face),截图里却变成了默认字体。 html2canvas 截图时,字体可能还没加载完,就用了默认字体渲染。 解决方法: 如果要截图的元素有滚动条,截图会包含滚动条,或者内容被截断。 解决方法: 如果页面里有 iframe,html2canvas 无法截图 iframe 里的内容。 同源策略限制,无法直接访问 iframe 内部的 DOM。 解决方法: 截图区域元素多、图片大时,生成 Canvas 会很慢,甚至浏览器卡顿。 解决方法: 直接截图 SVG 可能会变形、错位,甚至不显示。 解决方法: 截图里的元素层级和实际页面不一样,该在上面的元素跑到下面了。 html2canvas 对 解决方法: 点赞 + 关注 + 收藏 = 学会了html2canvas 简介
安装方法
1. npm /yarn 安装(推荐)
# npm 安装
npm install html2canvas
# yarn 安装
yarn add html2canvas2. CDN 引入
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>基础用法
div 转成 Canvas 并显示在页面上。
<template>
<div>
<!-- 要截图的区域 -->
<div ref="captureRef" style="padding: 20px; background: #f0f0f0;">
<p style="font-size: 16px; margin: 0;">随便写点什么,html2canvas 会把它变成图片~</p>
</div>
<!-- 截图按钮 -->
<button @click="handleCapture">点击截图</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import html2canvas from 'html2canvas'
// 获取要截图的 DOM 元素
const captureRef = ref(null)
// 截图函数
const handleCapture = async () => {
// 调用 html2canvas,等待生成 Canvas
const canvas = await html2canvas(captureRef.value)
// 把 Canvas 加到页面上看看效果
document.body.appendChild(canvas)
}
</script>h2,结果可能会出乎你所料。
<!-- 要截图的区域 -->
<div ref="captureRef" style="padding: 20px; background: #f0f0f0;">
<h2>雷猴</h2>
<p style="font-size: 16px; margin: 0;">随便写点什么,html2canvas 会把它变成图片~</p>
</div><h2> 标题的样式没跟着生成出来啊。。。
<template>
<div>
<!-- 要截图的区域 -->
<div
ref="captureRef"
class="capture-area"
style="padding: 20px; background: #f0f0f0;"
>
<!-- 关键样式建议写在行内,或者确保非 scoped -->
<h2 class="title">这是要截图的内容</h2>
<p style="font-size: 16px; margin: 0;">随便写点什么,html2canvas 会把它变成图片~</p>
</div>
<!-- 截图按钮 -->
<button @click="handleCapture">点击截图</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import html2canvas from 'html2canvas'
// 获取要截图的 DOM 元素
const captureRef = ref(null)
// 截图函数
const handleCapture = async () => {
// 调用 html2canvas,等待生成 Canvas
const canvas = await html2canvas(captureRef.value)
// 把 Canvas 加到页面上看看效果
document.body.appendChild(canvas)
}
</script>
<style scoped>
.capture-area {
width: 400px;
box-sizing: border-box;
border: 1px solid #ccc;
}
.title {
font-size: 24px;
font-weight: bold;
margin: 0 0 10px 0;
}
</style>常用配置选项
配置项 类型 默认值 说明 scalenumberwindow.devicePixelRatio缩放比例,默认用设备像素比,提高截图清晰度(设为 1 会模糊)。 useCORSbooleanfalse是否允许加载跨域图片,设为 true 才能正确显示跨域图片。backgroundColorstring#ffffffCanvas 背景色,设为 null 可以得到透明背景。loggingbooleanfalse是否在控制台打印日志,调试时可以设为 true 看问题。scrollXnumber0截图时的水平滚动偏移,解决页面滚动导致的内容错位。 scrollYnumber0截图时的垂直滚动偏移,同上。 
<template>
<div>
<!-- 要截图的区域 -->
<div
ref="captureRef"
class="capture-area"
style="padding: 20px; background: #f0f0f0;"
>
<!-- 关键样式建议写在行内,或者确保非 scoped -->
<h2 class="title">这是要截图的内容</h2>
<img src="https://iili.io/fcR7gSe.md.png" alt="" style="width: 140px;">
<p style="font-size: 16px; margin: 0;">随便写点什么,html2canvas 会把它变成图片~</p>
</div>
<!-- 截图按钮 -->
<button @click="handleCapture">点击截图</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import html2canvas from 'html2canvas'
// 获取要截图的 DOM 元素
const captureRef = ref(null)
// 截图函数
const handleCapture = async () => {
// 调用 html2canvas,等待生成 Canvas
const canvas = await html2canvas(captureRef.value)
// 把 Canvas 加到页面上看看效果
document.body.appendChild(canvas)
}
</script>
<style scoped>
.capture-area {
width: 400px;
box-sizing: border-box;
border: 1px solid #ccc;
}
.title {
font-size: 24px;
font-weight: bold;
margin: 0 0 10px 0;
}
</style>Access-Control-Allow-Origin: *(允许跨域)useCORS: truecrossorigin="anonymous" 属性。useCORS: true 即可。
// 省略部分代码
const canvas = await html2canvas(captureRef.value, {
useCORS: true
})高级用法:导出并下载图片
toDataURL 实现
<template>
<div>
<!-- 要截图的区域 -->
<div
ref="captureRef"
class="capture-area"
style="padding: 20px; background: #f0f0f0;"
>
<!-- 关键样式建议写在行内,或者确保非 scoped -->
<h2 class="title">这是要截图的内容</h2>
<img src="https://iili.io/fcR7gSe.md.png" alt="" style="width: 140px;">
<p style="font-size: 16px; margin: 0;">随便写点什么,html2canvas 会把它变成图片~</p>
</div>
<!-- 截图按钮 -->
<button @click="handleCapture">点击截图</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import html2canvas from 'html2canvas'
// 获取要截图的 DOM 元素
const captureRef = ref(null)
// 截图函数
const handleCapture = async () => {
// 调用 html2canvas,等待生成 Canvas
const canvas = await html2canvas(captureRef.value, { useCORS: true });
// 1. 把 Canvas 转成 PNG 格式的 base64 数据
const imgData = canvas.toDataURL('image/png');
// 2. 创建下载链接
const link = document.createElement('a');
link.download = '我的截图.png'; // 下载的文件名
link.href = imgData;
// 3. 触发点击下载
link.click();
}
</script>
<style scoped>
.capture-area {
width: 400px;
box-sizing: border-box;
border: 1px solid #ccc;
}
.title {
font-size: 24px;
font-weight: bold;
margin: 0 0 10px 0;
}
</style>常见坑点及避坑指南
跨域图片不显示或报错
Access-Control-Allow-Origin: *(允许跨域)crossorigin="anonymous" 属性useCORS: true<!-- 图片标签加 crossorigin -->
<img src="https://example.com/image.jpg" crossorigin="anonymous">CSS 样式显示异常
transform、box-shadow、复杂渐变、伪元素 ::before/::after)可能渲染不对,甚至完全不显示。自定义字体渲染失败
document.fonts.ready 即可document.getElementById('btn').addEventListener('click', async () => {
// 等待所有字体加载完成
await document.fonts.ready;
const element = document.getElementById('capture');
const canvas = await html2canvas(element);
document.body.appendChild(canvas);
});滚动条导致截图不全或有滚动条
const element = document.getElementById('capture');
// 保存原来的 overflow 样式
const originalOverflow = element.style.overflow;
// 隐藏滚动条
element.style.overflow = 'hidden';
const canvas = await html2canvas(element, {
scrollX: 0,
scrollY: 0 // 重置滚动偏移
});
// 恢复原来的样式
element.style.overflow = originalOverflow;iframe 内容无法捕获
页面元素太多导致性能差
scale(比如设为 1.5 而不是 2)display: none)SVG 元素显示异常
canvg 库辅助转换,或者手动把 SVG 转成 base64 图片// 简单的 SVG 转图片示例
const svgElement = document.querySelector('svg');
const svgData = new XMLSerializer().serializeToString(svgElement);
const img = new Image();
img.src = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgData)));
// 等图片加载完后,替换原来的 SVG,再截图
img.onload = async () => {
svgElement.parentNode.replaceChild(img, svgElement);
const canvas = await html2canvas(element);
document.body.appendChild(canvas);
};z-index 层级错乱
z-index 的解析有时会出问题,尤其是元素没有显式设置 position 时。position(如 relative、absolute)z-index