1.需求
由于在最近在做的項目需要用到在前端把頁面生成圖片并保存到手機中,在技術調用過程中自己寫了一個demo,沒有采用vue-cli腳手架,但是大同小異,這個demo也采用了vue2.js開發頁面,qrcode.js來生成二維碼,原理比較簡單。該demo項目:github地址 ,覺得有幫助的給一個星,萬分感謝。該項目不能直接打開index.html進行訪問,會出現報錯。請用 http-server
打開,不明白怎么配置可參考http-server開啟本地服務
在線預覽
具體的需求如下:
- 獲取后臺信息,得出排名和用戶圖像
2.點擊保存按鈕,把改頁面生成圖片
3.長按保存圖片或掃描二維碼
2.思路
- html2canvas.js:可將 htmldom 轉為 canvas 元素。
- canvasAPI:toDataUrl() 可將 canvas 轉為 base64 格式
- 在微信瀏覽器中,長按img,會彈起actionsheet,可以進行保存、發送、識別二維碼等操作
3.代碼分析
解決圖片模糊
在pc端開發時生成圖片沒有問題,但是在移動端會出現模糊的情況,主要原因是像素比的問題。
設備像素比 (簡稱 dpr) 定義了物理像素和設備獨立像素的對應關系,它的值可以按如下的公式的得到:
設備像素比 = 物理像素 / 設備獨立像素 // 在某一方向上,x方向或者y方向
解決代碼:
/**
* 根據 window.devicePixelRatio 獲取像素比
* @returns {number}
*/
changeDpr: function() {
if (window.devicePixelRatio && window.devicePixelRatio > 1) {
return window.devicePixelRatio;
}
return 1;
},
解決圖片不顯示問題
如果引用沒有跨域配置的圖片地址會出現一下報錯
Uncaught (in promise) DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
盡管不通過 CORS 就可以在畫布中使用圖片,但是這會污染畫布。一旦畫布被污染,你就無法讀取其數據。例如,你不能再使用畫布的 toBlob(), toDataURL() 或 getImageData() 方法,調用它們會拋出安全錯誤。
HTML 規范中圖片有一個 [crossorigin](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/img#attr-crossorigin)
屬性,結合合適的 CORS 響應頭,就可以實現在畫布中使用跨域 <img>
元素的圖像。
解決代碼如下:
// 將圖片轉為base64格式
imgTobase64: function(url, crossOrigin) {
return new Promise(resolve => {
const img = new Image();
img.onload = () => {
const c = document.createElement('canvas');
c.width = img.naturalWidth;
c.height = img.naturalHeight;
const cxt = c.getContext('2d');
cxt.drawImage(img, 0, 0);
// 得到圖片的base64編碼數據
resolve(c.toDataURL('image/png'));
};
// 結合合適的CORS響應頭,實現在畫布中使用跨域<img>元素的圖像
crossOrigin && img.setAttribute('crossOrigin', crossOrigin);
img.src = url;
});
}
生成圖片
圖片生成是利用canvas來進行獲取并生成圖片,有些需求需要導出長圖,可以改動一下代碼
// 設置需要生成的圖片的大小,不限于可視區域(即可保存長圖)
var w = dom.style.width;
var h = dom.style.height;
由于部分需求并不需要顯示個別的元素,可以利用 data-html2canvas-ignore
來進行忽略。如果在開始渲染不顯示,可以把它的透明度進行變化,在轉化之前設置為1即可。
下載后的圖片會覆蓋整個頁面,即長按就可以調用actionsheet進行操作。
代碼如下:
/**
* 生成圖片
*/
createImage: function() {
var _this = this;
// 獲取想要轉換的dom節點
// var dom = document.getElementById('app');
var dom = _this.$refs.app;
var box = window.getComputedStyle(dom);
// 顯示導出需要樣式
_this.$refs.scanText.style.opacity = '1'
// dom節點計算后寬高,轉為整數
var width = parseInt(box.width, 10);
var height = parseInt(box.height, 10);
// 獲取像素比
var scaleBy = _this.changeDpr();
// 創建自定義的canvas元素
var canvas = document.createElement('canvas');
// 設置canvas元素屬性寬高為 DOM 節點寬高 * 像素比
canvas.width = width * scaleBy;
canvas.height = height * scaleBy;
// 設置canvas css 寬高為DOM節點寬高
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';
// 獲取畫筆
var context = canvas.getContext('2d');
// 將所有繪制內容放大像素比倍
context.scale(scaleBy, scaleBy);
// 設置需要生成的圖片的大小,不限于可視區域(即可保存長圖)
var w = dom.style.width;
var h = dom.style.height;
html2canvas(dom, {
allowTaint: true,
width: w,
height: h,
useCORS: true
}).then(function(canvas) {
// 將canvas轉換成圖片渲染到頁面上
var url = canvas.toDataURL('image/png');// base64數據
var image = new Image();
image.src = url;
document.getElementById('shareImg').appendChild(image);
// 隱藏按鈕
_this.CanvasImageHide = false;
// 給渲染后圖片大小全屏
var shareImgElem = document.getElementById('shareImg');
shareImgElem.style.height = '100%'
});
}