最近在做活動頁,有個 H5 頁面生成海報圖片的功能,本來想著用后端做,但需要把前端代碼傳到后端,后端在解析生成圖片,返回前端,但這么雖然可以,但太麻煩了,并且耗時,雖然感覺減輕了前端的工作量,但后端工作量很大。讓后就去網(wǎng)上搜了一下 DOM 轉(zhuǎn) png,嘗試找一找有沒有這樣的庫,就找到了 html2canvas 這個庫。
記錄一下用法,以及遇到的坑及解決方式:
- 下載 npm i html2canvas 或 yarn add html2canvas
- 生成圖片
productionImage() {
// 手動創(chuàng)建一個 canvas 標簽
const canvas = document.createElement("canvas")
// 獲取父標簽,意思是這個標簽內(nèi)的 DOM 元素生成圖片
let canvasBox = this.$refs.imageWrapper
// 獲取父級的寬高
const width = parseInt(window.getComputedStyle(canvasBox).width)
const height = parseInt(window.getComputedStyle(canvasBox).height)
// 寬高 * 2 并放大 2 倍 是為了防止圖片模糊
canvas.width = width * 2
canvas.height = height * 2
canvas.style.width = width + 'px'
canvas.style.height = height + 'px'
const context = canvas.getContext("2d");
context.scale(2, 2);
const options = {
backgroundColor: null,
canvas: canvas,
useCORS: true
}
html2canvas(canvasBox, options).then((canvas) => {
// toDataURL 圖片格式轉(zhuǎn)成 base64
let dataURL = canvas.toDataURL("image/png")
this.downloadImage(dataURL)
})
},
downloadImage(url) {
// 創(chuàng)建一個 img 標簽,把圖片插入到 DOM 中
// 這里使用 img 是因為在客戶端中,不能直接下載,要調(diào)用原生的方法
const parents = this.$refs.selfReport
const createImg = document.createElement('img')
const insertEle = this.$refs.insetElement
parents.insertBefore(createImg,parents.childNodes[0])
createImg.setAttribute('src', url)
// 如果是在網(wǎng)頁中可以直接創(chuàng)建一個 a 標簽直接下載
let a = document.createElement('a')
a.href = url
a.download = '文件名'
a.click()
},
說一下遇到的問題
圖片的跨域,如果生成的 DOM 元素中有包含圖片,域名跟本地訪問域名不一致的話,會出現(xiàn)跨域。
添加 useCORS: true , 但我發(fā)現(xiàn)還可能會有跨域問題,還有兩種解決方式是: 直接后端返回的圖片轉(zhuǎn)成 base64 或者 把圖片放到統(tǒng)一域名下畫出來的圖片有白色的邊框
解決方式: 設(shè)置 backgroundColor: null 就可以了
把 H5 頁面生成二維碼,可以看我的另一個小文章 鏈接
其實很多場景下都是二維碼+圖片的方式,二者的順序是先生成二維碼,放到 DOM 中,在利用 html2canvas 把 DOM 生成圖片。
最近發(fā)現(xiàn)一個小問題
我在網(wǎng)頁中使用 html2canvas 時,即使使用的二倍圖,將 canvas 放大兩倍或者三倍之后,出現(xiàn)在效果還是模糊的一倍圖,最后發(fā)現(xiàn)它好像和電腦屏幕的分辨率有關(guān)系,在自己 Mac 上和在擴展屏幕上生成的圖片清晰度差了很多,解決方式: 就是在options 中寫死 scale 的倍數(shù)。