html2canvas.js實現前端將頁面轉化為圖片並長按下載

巴依發表於2019-03-21

1.需求

由於在最近在做的專案需要用到在前端把頁面生成圖片並儲存到手機中,在技術呼叫過程中自己寫了一個demo,沒有采用vue-cli腳手架,但是大同小異,這個demo也採用了vue2.js開發頁面,qrcode.js來生成二維碼,原理比較簡單。該demo專案:github地址 ,覺得有幫助的給一個星,萬分感謝。該專案不能直接開啟index.html進行訪問,會出現報錯。請用 http-server 開啟,不明白怎麼配置可參考http-server開啟本地服務

線上預覽

image.png

具體的需求如下:
  1. 獲取後臺資訊,得出排名和使用者影象
  2. 點選儲存按鈕,把改頁面生成圖片
  3. 長按儲存圖片或掃描二維碼

image.png
image.png
image.png

2.思路

  1. html2canvas.js:可將 htmldom 轉為 canvas 元素。
  2. canvasAPI:toDataUrl() 可將 canvas 轉為 base64 格式
  3. 在微信瀏覽器中,長按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%'
            });
        }
複製程式碼

相關文章