Vue3+Element Plus項目中使用html2canvas截圖方式
在現(xiàn)代 Web 應用開發(fā)中,常常需要將頁面中的某一部分內(nèi)容生成圖片,用于保存、打印或上傳。html2canvas 是一個非常流行的前端庫,它能將 HTML 元素“繪制”成 Canvas,進而導出為圖片。
本文將結(jié)合實際 Vue3 + Element Plus 項目代碼,深入剖析 html2canvas 的使用方法及常見注意事項。
一、項目背景
我們有一個考核表單頁面(TotalExamine.vue),用戶填寫考核信息后,系統(tǒng)需將下方的評分表格區(qū)域自動截圖,并作為附件上傳至服務器。
該功能的核心就是利用 html2canvas 對指定 DOM 區(qū)域進行截圖。
二、核心代碼分析
1. 引入依賴
import html2canvas from 'html2canvas'
確保已在項目中安裝:
npm install html2canvas
2. 指定截圖區(qū)域
通過 ref 獲取需要截圖的 DOM 元素:
<template>
<div class="bottomContainer" id="superMap" ref="imageContentRef">
<!-- 表格內(nèi)容 -->
<el-table :data="tableData">...</el-table>
</div>
</template>
<script setup>
const imageContentRef = ref(null)
</script>? 關(guān)鍵點:ref="imageContentRef" 綁定到需要截圖的容器上。
3. 觸發(fā)截圖并上傳
在提交按鈕點擊事件 handleSubmitFinal() 中執(zhí)行截圖邏輯:
async function handleSubmitFinal() {
formRef.value.validate(async valid => {
if (valid) {
// 1. 使用 html2canvas 截圖
const canvas = await html2canvas(imageContentRef.value)
// 2. 將 canvas 轉(zhuǎn)為 Blob
canvas.toBlob(async (blob) => {
// 3. 創(chuàng)建 File 對象
const file = new File([blob], '考核成績.png', { type: 'image/png' })
// 4. 構(gòu)造 FormData 用于上傳
const uploadForm = new FormData()
uploadForm.append('file', file)
// 5. 調(diào)用上傳接口
const res = await getOverallExamineUpload(uploadForm)
const fileId = res?.data[0].fileId
// 6. 提交完整表單數(shù)據(jù)(含 fileId)
const data = { ...formInline, fileId }
const resp = await getOverallExamineSave(data)
if (resp.code === 200) {
ElMessage.success('提交成功!')
}
}, 'image/png')
}
})
}? 流程清晰:驗證 → 截圖 → 轉(zhuǎn)文件 → 上傳 → 提交主數(shù)據(jù)。
三、使用 html2canvas 的注意事項(避坑指南)
1.異步渲染問題
html2canvas 是基于當前 DOM 狀態(tài)截圖的。如果目標區(qū)域包含動態(tài)加載的內(nèi)容(如表格數(shù)據(jù)異步獲?。?,必須確保 DOM 已完全渲染后再調(diào)用。
解決方案:
- 使用
nextTick()確保 DOM 更新完成。 - 或在數(shù)據(jù)加載完成后再觸發(fā)截圖。
在本例中,tableData 是靜態(tài)初始化的,所以無此問題。但若從 API 獲取,需加 await nextTick()。
2.跨域圖片無法渲染
如果截圖區(qū)域內(nèi)包含 <img> 標簽且圖片來自其他域名(如 CDN),默認情況下 html2canvas 會因 CORS 策略將其渲染為空白。
解決方案:
- 圖片服務器需設置
Access-Control-Allow-Origin。 - 或使用代理加載圖片。
- 或提前將圖片轉(zhuǎn)為 base64 內(nèi)聯(lián)。
本例未使用外部圖片,故安全。
3.CSS 樣式兼容性
html2canvas 并非 100% 支持所有 CSS 屬性。例如:
box-shadow、transform、filter可能失效。position: fixed元素可能錯位。- 自定義字體(如 iconfont)可能顯示為方塊。
建議:
- 盡量使用基礎(chǔ)樣式。
- 截圖前可臨時添加
.screenshot-mode類,覆蓋復雜樣式。 - 測試不同瀏覽器表現(xiàn)。
本項目使用 Element Plus 默認樣式,兼容性較好。
4.容器尺寸與滾動
若截圖區(qū)域有滾動條(如 el-table 設置了 height),html2canvas 默認只截取可視區(qū)域。
解決方案:
- 確保容器高度足夠容納全部內(nèi)容(如本例中
.bottomContainer高度由父級控制)。 - 或臨時修改容器樣式(如
overflow: visible)再截圖。
?? 5.Canvas 轉(zhuǎn) Blob 的兼容性
canvas.toBlob() 在部分舊瀏覽器(如 IE)不支持。
Polyfill 方案:
if (!HTMLCanvasElement.prototype.toBlob) {
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
value: function (callback, type, quality) {
const binStr = atob(this.toDataURL(type, quality).split(',')[1])
const arr = new Uint8Array(binStr.length)
for (let i = 0; i < binStr.length; i++) {
arr[i] = binStr.charCodeAt(i)
}
callback(new Blob([arr], { type: type || 'image/png' }))
}
})
}現(xiàn)代項目通常無需考慮,但需知曉。
四、優(yōu)化建議
截圖前隱藏無關(guān)元素
可臨時隱藏按鈕、滾動條等干擾項:
const el = imageContentRef.value
el.querySelector('.no-print')?.style.display = 'none'提升截圖清晰度
通過縮放提高分辨率:
const scale = window.devicePixelRatio || 2
const canvas = await html2canvas(el, { scale })錯誤處理
添加 try-catch 防止截圖失敗導致整個流程中斷。
五、總結(jié)
html2canvas 是實現(xiàn)前端“所見即所得”截圖的強大工具。在 Vue3 項目中,結(jié)合 ref 和 async/await 可輕松集成。但務必注意其局限性,尤其是在樣式兼容性和異步渲染方面。
通過本文的代碼分析與注意事項梳理,相信你能在自己的項目中更穩(wěn)健地使用 html2canvas,避免踩坑,高效交付功能!
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Vue $router.push打開新窗口的實現(xiàn)方法
在Vue中,$router.push方法默認不支持在新窗口中打開頁面,但通過結(jié)合window.open方法和$router.resolve方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-09-09
vue2自定義組件通過rollup配置發(fā)布到npm的詳細步驟
這篇文章主要介紹了vue2自定義組件通過rollup配置發(fā)布到npm,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03
Vue+elementUI實現(xiàn)多圖片上傳與回顯功能(含回顯后繼續(xù)上傳或刪除)
這篇文章主要介紹了Vue+elementUI實現(xiàn)多圖片上傳與回顯功能(含回顯后繼續(xù)上傳或刪除),本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03
vue項目出現(xiàn)ERESOLVE could not resolve問題及解決
這篇文章主要介紹了vue項目出現(xiàn)ERESOLVE could not resolve問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10

