前端html2canvas使用场景详解

html2canvas 是前端常用的 “DOM 转图片” 库,核心是将页面 DOM 节点渲染为 Canvas,再转为图片(Base64 或 Blob)。以下是 9 种核心使用场景的详细教程,包含代码示例、参数配置、问题解决,覆盖日常开发需求。

一、基础使用:将指定 DOM 转为 Base64 图片

适用于简单场景(如生成证书、截图分享),无需复杂配置。

1. 安装与引入

# npm 安装 npm install html2canvas --save 

javascript

// 模块化项目引入(Vue/React/Angular) import html2canvas from 'html2canvas'; // 非模块化项目(直接引入 CDN) <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/html2canvas.min.js"></script> 

2. 核心代码

html

<!-- 目标 DOM:需要转为图片的容器 --> <div> <h2>基础截图示例</h2> <p>这是要转为图片的内容</p> </div> <!-- 图片预览容器 --> <img /> 

javascript

// 触发截图(如点击按钮后) document.querySelector('#btn').addEventListener('click', async () => { // 1. 获取目标 DOM const targetDom = document.getElementById('targetDom'); // 2. 调用 html2canvas 生成 Canvas const canvas = await html2canvas(targetDom, { scale: 2, // 2倍缩放,避免图片模糊(关键参数) useCORS: true, // 允许跨域图片(如网络图片) logging: false, // 关闭控制台日志 backgroundColor: null // 保留 DOM 原有背景(默认白色) }); // 3. Canvas 转为 Base64 图片(支持 jpeg/png) const base64Img = canvas.toDataURL('image/jpeg', 1.0); // 1.0 表示质量(0-1) // 4. 预览图片 document.getElementById('previewImg').src = base64Img; // 5. (可选)下载图片 const link = document.createElement('a'); link.href = base64Img; link.download = '基础截图.jpg'; link.click(); }); 

二、进阶场景:处理跨域图片

当 DOM 中包含网络图片(如 https://xxx.com/xxx.jpg),易出现 “图片空白” 问题,需配置跨域参数。

关键配置

  1. 前端配置useCORS: true + allowTaint: true(允许跨域图片污染 Canvas);
  2. 后端配置:图片服务器需返回 Access-Control-Allow-Origin: *(或当前域名),否则跨域图片仍会空白。

完整代码

javascript

const canvas = await html2canvas(targetDom, { scale: 2, useCORS: true, // 允许加载跨域图片 allowTaint: true, // 允许 Canvas 被跨域图片污染(否则图片会被过滤) logging: false, // (可选)处理跨域图片加载失败的情况 onclone: (clonedDoc) => { // clonedDoc 是 DOM 克隆体,可在此修改图片地址 const imgs = clonedDoc.querySelectorAll('img'); imgs.forEach(img => { // 替换图片为同源地址(若后端未配置 CORS 时的备选方案) if (img.src.includes('跨域域名')) { img.src = img.src.replace('跨域域名', '同源代理域名'); } }); } }); 

三、复杂场景:固定宽高 + 滚动内容截图

适用于 “长列表截图”(如表格、聊天记录),需固定截图宽高,同时包含滚动区域的所有内容。

核心思路

  1. 先保存目标 DOM 的原始样式(overflow/height);
  2. 临时修改为 overflow: visible + 自适应高度(确保所有内容展开);
  3. 截图完成后恢复原始样式。

完整代码

javascript

async function captureScrollContent() { const targetDom = document.getElementById('targetDom'); // 1. 保存原始样式 const originalStyle = { overflow: targetDom.style.overflow, height: targetDom.style.height }; try { // 2. 临时修改样式:展开所有滚动内容 targetDom.style.overflow = 'visible'; targetDom.style.height = 'auto'; // 自适应高度,显示所有内容 // 3. 截图(固定宽高,避免内容变形) const canvas = await html2canvas(targetDom, { scale: 2, useCORS: true, logging: false, windowWidth: targetDom.offsetWidth, // 固定截图宽度 windowHeight: targetDom.offsetHeight // 固定截图高度(此时已包含所有内容) }); // 4. 转为图片并下载 const base64Img = canvas.toDataURL('image/png', 1.0); const link = document.createElement('a'); link.href = base64Img; link.download = '长列表截图.png'; link.click(); } finally { // 5. 恢复原始样式(无论成功失败都要恢复) targetDom.style.overflow = originalStyle.overflow; targetDom.style.height = originalStyle.height; } } // 调用 captureScrollContent(); 

四、Vue 项目:组件内 DOM 截图(含响应式数据)

Vue 中需注意 “DOM 渲染时机”—— 确保数据更新后(如接口请求完成)再截图,避免内容空白。

核心注意点

  1. 用 this.$nextTick() 确保 DOM 已更新;
  2. 若用 v-for 渲染列表,需等待列表渲染完成后再截图。

完整代码(Vue 3 示例)

vue

<template> <div> <!-- 目标 DOM:包含响应式数据 --> <div ref="certDom"> <h2>{{ userName }} 的证书</h2> <p>项目:{{ projectName }}</p> <p>时间:{{ date }}</p> </div> <button @click="generateCert">生成证书</button> <img :src="previewImg" alt="证书预览" /> </div> </template> <script setup> import { ref, nextTick } from 'vue'; import html2canvas from 'html2canvas'; // 响应式数据 const userName = ref(''); const projectName = ref(''); const date = ref('2025-01-01'); const previewImg = ref(''); const certDom = ref(null); // 目标 DOM 引用 // 接口请求:获取用户数据 const fetchUserInfo = async () => { const res = await fetch('/api/user'); const data = await res.json(); userName.value = data.userName; projectName.value = data.projectName; }; // 生成证书(截图) const generateCert = async () => { // 1. 先获取数据,确保 DOM 已更新 await fetchUserInfo(); // 2. 等待 Vue DOM 渲染完成 await nextTick(); // 3. 截图(certDom.value 是目标 DOM) const canvas = await html2canvas(certDom.value, { scale: 2, useCORS: true, backgroundColor: '#fff' }); // 4. 预览并下载 previewImg.value = canvas.toDataURL('image/jpeg', 1.0); const link = document.createElement('a'); link.href = previewImg.value; link.download = `${userName.value}的证书.jpg`; link.click(); }; </script> <style scoped> .cert-container { width: 500px; height: 700px; background: url('@/assets/cert-bg.jpg') no-repeat center; background-size: 100% 100%; padding: 50px; box-sizing: border-box; } </style> 

五、React 项目:函数组件截图(含 Hooks)

React 中需用 useRef 获取 DOM 节点,用 useEffect 处理异步渲染时机。

完整代码(React 18 示例)

jsx

import { useRef, useState } from 'react'; import html2canvas from 'html2canvas'; const ScreenshotComponent = () => { // 1. 获取目标 DOM 引用 const targetRef = useRef(null); // 2. 预览图片状态 const [previewImg, setPreviewImg] = useState(''); // 截图函数 const captureDom = async () => { if (!targetRef.current) return; // 3. 调用 html2canvas const canvas = await html2canvas(targetRef.current, { scale: 2, useCORS: true, logging: false }); // 4. 转为图片 const base64 = canvas.toDataURL('image/png', 1.0); setPreviewImg(base64); // 5. 下载图片 const link = document.createElement('a'); link.href = base64; link.download = 'react截图.png'; link.click(); }; return ( <div style={{ padding: 20 }}> {/* 目标 DOM:用 ref 绑定 */} <div ref={targetRef} style={{ width: 400, height: 300, background: '#e8f4f8', padding: 20 }} > <h3>React 截图示例</h3> <p>当前时间:{new Date().toLocaleString()}</p> </div> <button onClick={captureDom} style={{ margin: 20 }}>生成截图</button> {previewImg && <img src={previewImg} alt="预览" style={{ maxWidth: '100%' }} />} </div> ); }; export default ScreenshotComponent; 

六、特殊场景:隐藏 DOM 截图(不显示在页面)

适用于 “后台生成图片”(如生成后直接下载,无需在页面显示 DOM),需临时将 DOM 渲染到页面外。

核心思路

  1. 目标 DOM 初始样式设为 position: absolute; left: -9999px; top: -9999px;(隐藏在视口外);
  2. 截图完成后可删除该 DOM(可选)。

完整代码

html

<!-- 隐藏的目标 DOM:在视口外渲染 --> <div> <h2>隐藏 DOM 生成的图片</h2> <p>用户:张三</p> <p>等级:VIP</p> </div> <button>生成隐藏图片</button> 

javascript

document.getElementById('generateBtn').addEventListener('click', async () => { const hiddenDom = document.getElementById('hiddenDom'); // 截图(与正常 DOM 一致) const canvas = await html2canvas(hiddenDom, { scale: 2, useCORS: true, logging: false }); // 下载图片 const base64 = canvas.toDataURL('image/jpeg', 1.0); const link = document.createElement('a'); link.href = base64; link.download = '隐藏DOM图片.jpg'; link.click(); // (可选)截图后删除隐藏 DOM // hiddenDom.remove(); }); 

七、性能优化:批量截图 + 避免重复渲染

当需要批量生成图片(如多条数据生成证书),需控制截图顺序,避免同时渲染导致浏览器卡顿。

核心思路

  1. 用 async/await 按顺序截图(一条完成后再截下一条);
  2. 截图前判断是否已生成,避免重复操作。

完整代码

javascript

// 批量数据(如多条证书信息) const certList = [ { id: 1, userName: '张三', project: '前端开发' }, { id: 2, userName: '李四', project: '后端开发' }, { id: 3, userName: '王五', project: 'UI设计' } ]; // 批量截图函数 async function batchCapture() { for (const cert of certList) { // 1. 动态创建目标 DOM(每条数据一个 DOM) const tempDom = document.createElement('div'); tempDom.style.width = '500px'; tempDom.style.height = '700px'; tempDom.style.background = '#fff'; tempDom.style.padding = '50px'; tempDom.style.position = 'absolute'; tempDom.style.left = '-9999px'; // 隐藏在视口外 tempDom.innerHTML = ` <h2>${cert.userName} 的证书</h2> <p>项目:${cert.project}</p> <p>日期:2025-01-01</p> `; document.body.appendChild(tempDom); try { // 2. 截图(按顺序执行) const canvas = await html2canvas(tempDom, { scale: 2, useCORS: true, logging: false }); // 3. 下载图片 const base64 = canvas.toDataURL('image/jpeg', 1.0); const link = document.createElement('a'); link.href = base64; link.download = `${cert.userName}的证书.jpg`; link.click(); } finally { // 4. 移除临时 DOM(避免内存占用) document.body.removeChild(tempDom); // (可选)延迟 500ms,避免浏览器卡顿 await new Promise(resolve => setTimeout(resolve, 500)); } } } // 调用批量截图 batchCapture(); 

八、问题解决:常见报错与优化方案

1. 图片模糊

  • 原因:Canvas 默认缩放为 1,屏幕 DPI 过高(如 Retina 屏)导致模糊;
  • 解决:设置 scale: 2 或 scale: window.devicePixelRatio(自适应屏幕 DPI)。

javascript

const canvas = await html2canvas(targetDom, { scale: window.devicePixelRatio, // 自适应屏幕缩放 useCORS: true }); 

2. 跨域图片空白

  • 原因:图片服务器未配置 CORS,或未开启 useCORS: true
  • 解决
    1. 后端添加 Access-Control-Allow-Origin 响应头;
    2. 前端配置 useCORS: true + allowTaint: true
    3. 备选方案:用同源代理服务器转发图片(如 Nginx 代理)。

3. DOM 内容未完全渲染(如接口数据空白)

  • 原因:截图时机过早,DOM 尚未更新(如接口请求未完成);
  • 解决
    • Vue:用 this.$nextTick() 等待 DOM 渲染;
    • React:用 useEffect 或 await 等待数据加载;
    • 原生 JS:在接口 then 回调中执行截图。

4. 大 DOM 截图卡顿

  • 原因:DOM 节点过多(如长列表、复杂表格),渲染耗时;
  • 解决
    1. 简化 DOM(移除截图无关的节点,如隐藏按钮、多余注释);
    2. 分批截图(避免一次性渲染大量节点);
    3. 关闭日志:logging: false(减少控制台输出耗时)。

九、高级场景:Canvas 转 Blob 上传服务器

当需要将生成的图片上传到后端(而非本地下载),需将 Canvas 转为 Blob 格式(比 Base64 更节省带宽)。

完整代码

javascript

async function captureAndUpload() { const targetDom = document.getElementById('targetDom'); const canvas = await html2canvas(targetDom, { scale: 2, useCORS: true, logging: false }); // 1. Canvas 转为 Blob(支持指定格式和质量) canvas.toBlob(async (blob) => { // 2. 构建 FormData(用于上传) const formData = new FormData(); formData.append('image', blob, '上传图片.jpg'); // 第三个参数是文件名 formData.append('userId', '123'); // 其他参数(如用户ID) // 3. 上传到服务器 try { const res = await fetch('/api/upload-image', { method: 'POST', body: formData, // 注意:FormData 上传无需设置 Content-Type,浏览器会自动处理 }); const data = await res.json(); if (data.success) { alert('图片上传成功!'); console.log('图片地址:', data.imageUrl); } } catch (err) { console.error('上传失败:', err); } }, 'image/jpeg', 0.8); // 0.8 表示图片质量(0-1,值越高质量越好) } // 调用 captureAndUpload();

Read more

【案例共创】基于华为开发者空间-云开发环境(容器)与Versatile Agent构建AI轻量级智能笑话机器人助手

【案例共创】基于华为开发者空间-云开发环境(容器)与Versatile Agent构建AI轻量级智能笑话机器人助手

最新案例动态,请查阅【案例共创】基于华为开发者空间-云开发环境(容器)与Versatile Agent构建AI轻量级智能笑话机器人助手。小伙伴们快来进行实操吧! 本案例由开发者:liujxu提供 一、概述 1.1 适用对象 * 个人开发者 * 高校学生 1.2 案例流程 本案例基于华为开发者空间-云开发环境(容器)与Versatile Agent,构建一个轻量级、趣味性强的AI应用——“智能笑话机器人”。该机器人能够理解用户的意图,并以一个幽默风趣的喜剧演员的口吻,为用户提供源源不断的笑话,为日常生活增添一份乐趣。 通过本案例的实践,开发者可以体验到从Versatile Agent智能体(Agent)的创建、后端服务的开发,到最终Web应用部署的全过程。这不仅是一个有趣的AI应用开发入门教程,也是一个展示如何将大型语言模型(LLM)的能力快速封装成具体产品的典型示例。 说明: 1. 登录华为开发者空间,VS Code安装Huawei Developer Space插件,远程创建、

基于STM32的智能家居安防系统设计与实现(完整项目)

基于STM32的智能家居安防系统设计与实现(完整项目)

基于STM32的智能家居安防系统设计与实现 摘要 随着物联网技术、嵌入式技术和智能控制技术的快速发展,智能家居安防系统逐渐成为现代家庭生活的重要组成部分,其能够实时监测家庭环境安全状态、防范安全隐患,为居民提供安全、便捷、舒适的居住环境。传统家庭安防方式多采用单一设备监测,存在功能分散、监测不全面、无法远程管控、报警响应滞后等问题,难以满足现代家庭对安防的多元化、智能化需求。 本文设计并实现了一套基于STM32F103C8T6单片机的智能家居安防系统,整合密码锁、温湿度采集、煤气烟雾检测、火灾报警、防盗报警、远程照明控制、实时时钟显示、OLED本地显示、WiFi手机APP远程监控、APP远程时间修改、本地蜂鸣器报警与远程报警联动等11项核心功能,构建了完整的智能家居安防系统架构。系统以STM32F103C8T6为核心控制单元,搭载密码锁模块、温湿度传感器、煤气烟雾传感器、火焰传感器、人体红外/门磁传感器、蜂鸣器报警模块、LED照明模块、实时时钟模块、OLED显示模块及WiFi通信模块,通过多模块协同工作,实现家庭安防的全方位监测、本地与远程双重管控,兼顾安全性、便捷性和实用性。

75元!复刻Moji 2.0 小智 AI 桌面机器人,基于乐鑫ESP32开发板,内置DeepSeek、Qwen大模型

文末联系小编,获取项目源码 Moji 2.0 是一个栖息在你桌面上的“有灵魂的伴侣”,采用乐鑫 ESP32-C5开发板,配置 1.5寸 360x360 高清屏,FPC 插接方式,支持 5G Wi-Fi 6 极速连接,内置小智 AI 2.0 系统,主要充当智能电子宠物的角色,在你工作学习枯燥时,通过圆形屏幕上的动态表情包卖萌解压,提供情绪陪伴;同时它也是功能强大的AI 语音助手,支持像真人一样流畅的连续对话,随时为你查询天气、解答疑惑或闲聊解闷,非常适合作为极客桌搭或嵌入式学习的开源平台。 🛠️ 装配进化 告别手焊屏幕的噩梦。全新设计的 FPC 插座连接,排线一插即锁,将复刻门槛降至最低。 🚀 性能进化 主控升级为 ESP32-C5。支持 5GHz Wi-Fi 6,

lingbot-depth-vitl14企业应用指南:机器人避障系统中替代高精度LiDAR的降本方案

lingbot-depth-vitl14企业应用指南:机器人避障系统中替代高精度LiDAR的降本方案 想让你的机器人“看”得更远、更准,又不想为昂贵的激光雷达买单?今天,我们就来聊聊一个能帮你省下大笔硬件成本的技术方案——lingbot-depth-vitl14深度估计模型。 简单来说,这个模型能让你的机器人用普通的RGB摄像头,就“猜”出周围环境的深度信息,实现精准避障。它就像一个给机器人安装的“空间感知大脑”,把二维的彩色画面,转换成三维的距离地图。 对于企业而言,这意味着什么?意味着你可以用几百块的摄像头,去实现过去需要几万甚至十几万激光雷达才能做到的部分功能。这不仅仅是省钱,更是为机器人、自动驾驶、AR/VR等应用打开了低成本、高性能的新大门。 接下来,我会带你深入了解这个模型,看看它如何在机器人避障这个核心场景中,真正落地并创造价值。 1. 为什么机器人避障需要深度信息? 在聊技术方案之前,我们先得搞清楚一个基本问题:机器人是怎么“看见”并避开障碍物的? 想象一下,你蒙着眼睛在房间里走路,很容易撞到桌子椅子。机器人也一样,它需要知道“前面有没有东西”以及“那个