前端html2canvas使用場景的詳細(xì)教程
前言
html2canvas 是前端常用的 “DOM 轉(zhuǎn)圖片” 庫,核心是將頁面 DOM 節(jié)點(diǎn)渲染為 Canvas,再轉(zhuǎn)為圖片(Base64 或 Blob)。以下是 9 種核心使用場景的詳細(xì)教程,包含代碼示例、參數(shù)配置、問題解決,覆蓋日常開發(fā)需求。
一、基礎(chǔ)使用:將指定 DOM 轉(zhuǎn)為 Base64 圖片
適用于簡單場景(如生成證書、截圖分享),無需復(fù)雜配置。
1. 安裝與引入
# npm 安裝 npm install html2canvas --save
javascript
// 模塊化項(xiàng)目引入(Vue/React/Angular) import html2canvas from 'html2canvas'; // 非模塊化項(xiàng)目(直接引入 CDN) <script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
2. 核心代碼
html
<!-- 目標(biāo) DOM:需要轉(zhuǎn)為圖片的容器 --> <div id="targetDom" style="width: 300px; height: 200px; background: #f5f5f5; padding: 20px;"> <h2>基礎(chǔ)截圖示例</h2> <p>這是要轉(zhuǎn)為圖片的內(nèi)容</p> </div> <!-- 圖片預(yù)覽容器 --> <img id="previewImg" style="margin-top: 20px; max-width: 100%;" />
javascript
// 觸發(fā)截圖(如點(diǎn)擊按鈕后)
document.querySelector('#btn').addEventListener('click', async () => {
// 1. 獲取目標(biāo) DOM
const targetDom = document.getElementById('targetDom');
// 2. 調(diào)用 html2canvas 生成 Canvas
const canvas = await html2canvas(targetDom, {
scale: 2, // 2倍縮放,避免圖片模糊(關(guān)鍵參數(shù))
useCORS: true, // 允許跨域圖片(如網(wǎng)絡(luò)圖片)
logging: false, // 關(guān)閉控制臺(tái)日志
backgroundColor: null // 保留 DOM 原有背景(默認(rèn)白色)
});
// 3. Canvas 轉(zhuǎn)為 Base64 圖片(支持 jpeg/png)
const base64Img = canvas.toDataURL('image/jpeg', 1.0); // 1.0 表示質(zhì)量(0-1)
// 4. 預(yù)覽圖片
document.getElementById('previewImg').src = base64Img;
// 5. (可選)下載圖片
const link = document.createElement('a');
link.href = base64Img;
link.download = '基礎(chǔ)截圖.jpg';
link.click();
});
二、進(jìn)階場景:處理跨域圖片
當(dāng) DOM 中包含網(wǎng)絡(luò)圖片(如 https://xxx.com/xxx.jpg),易出現(xiàn) “圖片空白” 問題,需配置跨域參數(shù)。
關(guān)鍵配置
- 前端配置:
useCORS: true+allowTaint: true(允許跨域圖片污染 Canvas); - 后端配置:圖片服務(wù)器需返回
Access-Control-Allow-Origin: *(或當(dāng)前域名),否則跨域圖片仍會(huì)空白。
完整代碼
javascript
const canvas = await html2canvas(targetDom, {
scale: 2,
useCORS: true, // 允許加載跨域圖片
allowTaint: true, // 允許 Canvas 被跨域圖片污染(否則圖片會(huì)被過濾)
logging: false,
// (可選)處理跨域圖片加載失敗的情況
onclone: (clonedDoc) => {
// clonedDoc 是 DOM 克隆體,可在此修改圖片地址
const imgs = clonedDoc.querySelectorAll('img');
imgs.forEach(img => {
// 替換圖片為同源地址(若后端未配置 CORS 時(shí)的備選方案)
if (img.src.includes('跨域域名')) {
img.src = img.src.replace('跨域域名', '同源代理域名');
}
});
}
});
三、復(fù)雜場景:固定寬高 + 滾動(dòng)內(nèi)容截圖
適用于 “長列表截圖”(如表格、聊天記錄),需固定截圖寬高,同時(shí)包含滾動(dòng)區(qū)域的所有內(nèi)容。
核心思路
- 先保存目標(biāo) DOM 的原始樣式(
overflow/height); - 臨時(shí)修改為
overflow: visible+ 自適應(yīng)高度(確保所有內(nèi)容展開); - 截圖完成后恢復(fù)原始樣式。
完整代碼
javascript
async function captureScrollContent() {
const targetDom = document.getElementById('targetDom');
// 1. 保存原始樣式
const originalStyle = {
overflow: targetDom.style.overflow,
height: targetDom.style.height
};
try {
// 2. 臨時(shí)修改樣式:展開所有滾動(dòng)內(nèi)容
targetDom.style.overflow = 'visible';
targetDom.style.height = 'auto'; // 自適應(yīng)高度,顯示所有內(nèi)容
// 3. 截圖(固定寬高,避免內(nèi)容變形)
const canvas = await html2canvas(targetDom, {
scale: 2,
useCORS: true,
logging: false,
windowWidth: targetDom.offsetWidth, // 固定截圖寬度
windowHeight: targetDom.offsetHeight // 固定截圖高度(此時(shí)已包含所有內(nèi)容)
});
// 4. 轉(zhuǎn)為圖片并下載
const base64Img = canvas.toDataURL('image/png', 1.0);
const link = document.createElement('a');
link.href = base64Img;
link.download = '長列表截圖.png';
link.click();
} finally {
// 5. 恢復(fù)原始樣式(無論成功失敗都要恢復(fù))
targetDom.style.overflow = originalStyle.overflow;
targetDom.style.height = originalStyle.height;
}
}
// 調(diào)用
captureScrollContent();
四、Vue 項(xiàng)目:組件內(nèi) DOM 截圖(含響應(yīng)式數(shù)據(jù))
Vue 中需注意 “DOM 渲染時(shí)機(jī)”—— 確保數(shù)據(jù)更新后(如接口請(qǐng)求完成)再截圖,避免內(nèi)容空白。
核心注意點(diǎn)
- 用
this.$nextTick()確保 DOM 已更新; - 若用
v-for渲染列表,需等待列表渲染完成后再截圖。
完整代碼(Vue 3 示例)
vue
<template>
<div>
<!-- 目標(biāo) DOM:包含響應(yīng)式數(shù)據(jù) -->
<div ref="certDom" class="cert-container">
<h2>{{ userName }} 的證書</h2>
<p>項(xiàng)目:{{ projectName }}</p>
<p>時(shí)間:{{ date }}</p>
</div>
<button @click="generateCert">生成證書</button>
<img :src="previewImg" alt="證書預(yù)覽" style="max-width: 100%; margin-top: 20px;" />
</div>
</template>
<script setup>
import { ref, nextTick } from 'vue';
import html2canvas from 'html2canvas';
// 響應(yīng)式數(shù)據(jù)
const userName = ref('');
const projectName = ref('');
const date = ref('2025-01-01');
const previewImg = ref('');
const certDom = ref(null); // 目標(biāo) DOM 引用
// 接口請(qǐng)求:獲取用戶數(shù)據(jù)
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. 先獲取數(shù)據(jù),確保 DOM 已更新
await fetchUserInfo();
// 2. 等待 Vue DOM 渲染完成
await nextTick();
// 3. 截圖(certDom.value 是目標(biāo) DOM)
const canvas = await html2canvas(certDom.value, {
scale: 2,
useCORS: true,
backgroundColor: '#fff'
});
// 4. 預(yù)覽并下載
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 項(xiàng)目:函數(shù)組件截圖(含 Hooks)
React 中需用 useRef 獲取 DOM 節(jié)點(diǎn),用 useEffect 處理異步渲染時(shí)機(jī)。
完整代碼(React 18 示例)
jsx
import { useRef, useState } from 'react';
import html2canvas from 'html2canvas';
const ScreenshotComponent = () => {
// 1. 獲取目標(biāo) DOM 引用
const targetRef = useRef(null);
// 2. 預(yù)覽圖片狀態(tài)
const [previewImg, setPreviewImg] = useState('');
// 截圖函數(shù)
const captureDom = async () => {
if (!targetRef.current) return;
// 3. 調(diào)用 html2canvas
const canvas = await html2canvas(targetRef.current, {
scale: 2,
useCORS: true,
logging: false
});
// 4. 轉(zhuǎn)為圖片
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 }}>
{/* 目標(biāo) DOM:用 ref 綁定 */}
<div
ref={targetRef}
style={{ width: 400, height: 300, background: '#e8f4f8', padding: 20 }}
>
<h3>React 截圖示例</h3>
<p>當(dāng)前時(shí)間:{new Date().toLocaleString()}</p>
</div>
<button onClick={captureDom} style={{ margin: 20 }}>生成截圖</button>
{previewImg && <img src={previewImg} alt="預(yù)覽" style={{ maxWidth: '100%' }} />}
</div>
);
};
export default ScreenshotComponent;
六、特殊場景:隱藏 DOM 截圖(不顯示在頁面)
適用于 “后臺(tái)生成圖片”(如生成后直接下載,無需在頁面顯示 DOM),需臨時(shí)將 DOM 渲染到頁面外。
核心思路
- 目標(biāo) DOM 初始樣式設(shè)為
position: absolute; left: -9999px; top: -9999px;(隱藏在視口外); - 截圖完成后可刪除該 DOM(可選)。
完整代碼
html
<!-- 隱藏的目標(biāo) DOM:在視口外渲染 --> <div id="hiddenDom" style="position: absolute; left: -9999px; top: -9999px; width: 500px; height: 300px; background: #fff; padding: 30px;"> <h2>隱藏 DOM 生成的圖片</h2> <p>用戶:張三</p> <p>等級(jí):VIP</p> </div> <button id="generateBtn">生成隱藏圖片</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();
});
七、性能優(yōu)化:批量截圖 + 避免重復(fù)渲染
當(dāng)需要批量生成圖片(如多條數(shù)據(jù)生成證書),需控制截圖順序,避免同時(shí)渲染導(dǎo)致瀏覽器卡頓。
核心思路
- 用
async/await按順序截圖(一條完成后再截下一條); - 截圖前判斷是否已生成,避免重復(fù)操作。
完整代碼
javascript
// 批量數(shù)據(jù)(如多條證書信息)
const certList = [
{ id: 1, userName: '張三', project: '前端開發(fā)' },
{ id: 2, userName: '李四', project: '后端開發(fā)' },
{ id: 3, userName: '王五', project: 'UI設(shè)計(jì)' }
];
// 批量截圖函數(shù)
async function batchCapture() {
for (const cert of certList) {
// 1. 動(dòng)態(tài)創(chuàng)建目標(biāo) DOM(每條數(shù)據(jù)一個(gè) 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>項(xiàng)目:${cert.project}</p>
<p>日期:2025-01-01</p>
`;
document.body.appendChild(tempDom);
try {
// 2. 截圖(按順序執(zhí)行)
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. 移除臨時(shí) DOM(避免內(nèi)存占用)
document.body.removeChild(tempDom);
// (可選)延遲 500ms,避免瀏覽器卡頓
await new Promise(resolve => setTimeout(resolve, 500));
}
}
}
// 調(diào)用批量截圖
batchCapture();
八、問題解決:常見報(bào)錯(cuò)與優(yōu)化方案
1. 圖片模糊
- 原因:Canvas 默認(rèn)縮放為 1,屏幕 DPI 過高(如 Retina 屏)導(dǎo)致模糊;
- 解決:設(shè)置
scale: 2或scale: window.devicePixelRatio(自適應(yīng)屏幕 DPI)。
javascript
const canvas = await html2canvas(targetDom, {
scale: window.devicePixelRatio, // 自適應(yīng)屏幕縮放
useCORS: true
});
2. 跨域圖片空白
- 原因:圖片服務(wù)器未配置 CORS,或未開啟
useCORS: true; - 解決:
后端添加
Access-Control-Allow-Origin響應(yīng)頭;前端配置
useCORS: true+allowTaint: true;備選方案:用同源代理服務(wù)器轉(zhuǎn)發(fā)圖片(如 Nginx 代理)。
3. DOM 內(nèi)容未完全渲染(如接口數(shù)據(jù)空白)
- 原因:截圖時(shí)機(jī)過早,DOM 尚未更新(如接口請(qǐng)求未完成);
- 解決:
- Vue:用
this.$nextTick()等待 DOM 渲染; - React:用
useEffect或await等待數(shù)據(jù)加載; - 原生 JS:在接口
then回調(diào)中執(zhí)行截圖。
- Vue:用
4. 大 DOM 截圖卡頓
- 原因:DOM 節(jié)點(diǎn)過多(如長列表、復(fù)雜表格),渲染耗時(shí);
- 解決:
簡化 DOM(移除截圖無關(guān)的節(jié)點(diǎn),如隱藏按鈕、多余注釋);
分批截圖(避免一次性渲染大量節(jié)點(diǎn));
關(guān)閉日志:
logging: false(減少控制臺(tái)輸出耗時(shí))。
九、高級(jí)場景:Canvas 轉(zhuǎn) Blob 上傳服務(wù)器
當(dāng)需要將生成的圖片上傳到后端(而非本地下載),需將 Canvas 轉(zhuǎn)為 Blob 格式(比 Base64 更節(jié)省帶寬)。
完整代碼
javascript
async function captureAndUpload() {
const targetDom = document.getElementById('targetDom');
const canvas = await html2canvas(targetDom, {
scale: 2,
useCORS: true,
logging: false
});
// 1. Canvas 轉(zhuǎn)為 Blob(支持指定格式和質(zhì)量)
canvas.toBlob(async (blob) => {
// 2. 構(gòu)建 FormData(用于上傳)
const formData = new FormData();
formData.append('image', blob, '上傳圖片.jpg'); // 第三個(gè)參數(shù)是文件名
formData.append('userId', '123'); // 其他參數(shù)(如用戶ID)
// 3. 上傳到服務(wù)器
try {
const res = await fetch('/api/upload-image', {
method: 'POST',
body: formData,
// 注意:FormData 上傳無需設(shè)置 Content-Type,瀏覽器會(huì)自動(dòng)處理
});
const data = await res.json();
if (data.success) {
alert('圖片上傳成功!');
console.log('圖片地址:', data.imageUrl);
}
} catch (err) {
console.error('上傳失?。?, err);
}
}, 'image/jpeg', 0.8); // 0.8 表示圖片質(zhì)量(0-1,值越高質(zhì)量越好)
}
// 調(diào)用
captureAndUpload();總結(jié)
到此這篇關(guān)于前端html2canvas使用場景的文章就介紹到這了,更多相關(guān)前端html2canvas使用場景內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
微信小程序?qū)隫ant報(bào)錯(cuò)VM292:1 thirdScriptError的解決方法
這篇文章主要給大家介紹了關(guān)于微信小程序?qū)隫ant報(bào)錯(cuò)VM292:1 thirdScriptError的解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用微信小程序具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
event.x,event.clientX,event.offsetX區(qū)別
event.x,event.clientX,event.offsetX區(qū)別,需要的朋友可以參考下。2006-11-11
JavaScript創(chuàng)建數(shù)組的方法詳解
這篇文章主要為大家介紹了JavaScript創(chuàng)建數(shù)組的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2021-12-12
跟我學(xué)習(xí)javascript的prototype原型和原型鏈
跟我學(xué)習(xí)javascript的prototype原型和原型鏈,感興趣的小伙伴們可以參考一下2015-11-11
javascript中html字符串轉(zhuǎn)化為jquery dom對(duì)象的方法
最近項(xiàng)目需求要開發(fā)百度地圖相關(guān)的一個(gè)應(yīng)用,需要從硬編碼的html字符串中提取自己想要的元素以及屬性信息,由于在js中或者jq中操作元素節(jié)點(diǎn)以及屬性都是使用dom對(duì)象或者jq對(duì)象。下面介紹javascript中html字符串轉(zhuǎn)化為jquery dom對(duì)象的方法,需要的朋友可以參考下2015-08-08
javascript控制frame,iframe的src屬性代碼
原理就是通過獲取當(dāng)前網(wǎng)頁地址欄的信息傳參,然后設(shè)置框架的地址。2009-12-12
js控制輸入框獲得和失去焦點(diǎn)時(shí)狀態(tài)顯示的方法
這篇文章主要介紹了js控制輸入框獲得和失去焦點(diǎn)時(shí)狀態(tài)顯示的方法,可實(shí)現(xiàn)判斷輸入框的焦點(diǎn)狀態(tài)設(shè)置不同樣式的功能,是非常實(shí)用的技巧,需要的朋友可以參考下2015-01-01
JavaScript刪除數(shù)組中指定元素5種方法例子
這篇文章主要給大家介紹了關(guān)于JavaScript刪除數(shù)組中指定元素5種方法,在最近的項(xiàng)目中,有用到j(luò)s對(duì)數(shù)組的操作,所以這里總結(jié)一下,需要的朋友可以參考下2023-07-07

