layui中實現上傳圖片壓縮

1、關於js上傳圖片壓縮的方法,百度有不少種方法,這裏我參考修改了一下:html

function photoCompress(file, w, objDiv) {
    var ready = new FileReader();
    /*開始讀取指定的Blob對象或File對象中的內容. 當讀取操做完成時,readyState屬性的值會成爲DONE,若是設置了onloadend事件處理程序,則調用之.同時,result屬性中將包含一個data: URL格式的字符串以表示所讀取文件的內容.*/
    ready.readAsDataURL(file);
    ready.onload = function() {
        var re = this.result;
        canvasDataURL(re, w, objDiv);
    }
};
function canvasDataURL(path, obj, callback) {
    var img = new Image();
    img.src = path;
    img.onload = function() {
        var that = this;
        // 默認按比例壓縮
        var w = that.width,
            h = that.height,
            scale = w / h;
        w = obj.width || w;
        h = obj.height || (w / scale);
        var quality = 0.5; // 默認圖片質量爲0.7
        //生成canvas
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        // 建立屬性節點
        var anw = document.createAttribute("width");
        anw.nodeValue = w;
        var anh = document.createAttribute("height");
        anh.nodeValue = h;
        canvas.setAttributeNode(anw);
        canvas.setAttributeNode(anh);
        ctx.drawImage(that, 0, 0, w, h);
        // 圖像質量
        if(obj.quality && obj.quality <= 1 && obj.quality > 0) {
            quality = obj.quality;
        }
        // quality值越小,所繪製出的圖像越模糊
        var base64 = canvas.toDataURL('image/jpeg', quality);
        // 回調函數返回base64的值
        callback(base64);
    }
}
function convertBase64UrlToBlob(urlData) {
    var arr = urlData.split(','),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
    while(n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], {
        type: mime
    });
}

以上是壓縮圖片的方法,核心是將圖片放入canvas內,再用canvas.toDataURL方法進行壓縮,最後生成一個Blob對象。node

注:由於牽扯到canvas,因此低版本瀏覽器應該是不支持的吧(有待考證)ajax

 

2、圖片壓縮的方法有了,怎麼使用呢?怎麼上傳到後臺呢?往下看!canvas

html部分:瀏覽器

   
        <form action="file/uploadDoc" enctype="multipart/form-data" method="post" id="form">
            <input type="file" id="file" name="file" />
            <input type="submit" value="上傳" />
        </form>
 

 

 

js部分:async

      $("#file").change(function() {
                var formData = new formData("form");
                var file = this.files[0];
                photoCompress(file, {
                    quality: 0.5,
                }, function(base64Codes) {
                    var bl = convertBase64UrlToBlob(base64Codes);
                    formData.set("file", bl, file.name);
                });
            });

當選擇文件之後,使用photoCompress方法對上傳的圖片進行壓縮,photoCompress方法的第二個參數還能夠傳入長寬等參數,具體能夠看photoCompress這個方法,quality是用來設置壓縮後圖片質量的,越小質量越差,表現出來就是圖片越模糊,可是相應的體積就越小。ide

最後使用formData.set(key,value,name)方法,將現有的name爲file的表單元素的值改變。這個方法有三個參數,第一個是key值,也就是表單裏對應的元素的name值(若是不存在會自行添加),第二個值是value值,第三個是選填的值,若是第二個值爲blob對象或者file對象,則第三個值表示文件名。函數

 

固然,若是你不想用form表單提交,你也能夠用ajax提交的方法:post

html:   ui

 

        <form enctype="multipart/form-data" method="post" id="form">
            <input type="file" id="file" name="file" />
            <input type="button" value="上傳" id="uploadBtn"/>
        </form>

 

 

 

有些許的變化,form沒有了action,上傳的按鈕type改成了button

js部分給按鈕添加一個點擊事件,其餘也沒有變化,不作過多贅述:

            $("#uploadBtn").click(function () {
                var formData = new formData("form");
                $.ajax({
                    type:"post",
                    url:"",
                    async:true,
                    data:formData,
                    success:function (data) {
                        
                    },
                    error:function (e) {
                        
                    }
                });
            });

 

 

3、結合layui踩的一些坑,以及最終的解決方法。

先看html部分:

<button type="button" class="layui-btn" id="upImg">上傳圖片</button>
<div id="img_list">
</div>
<input type="button" id = "btnHide" class="none">

 

就是這麼簡單。爲何要再寫一個隱藏的按鈕,以後解釋。

js部分:

            layui.use('upload', function() {
                var upload = layui.upload;
                var uploadInst = upload.render({
                    elem: '#upImg',
                    url: '/upload/',
                    auto: false,
                    bindAction: "#btnHide",
                    choose: function(obj) {
                        var files = obj.pushFile();
                        var index, file, indexArr = [];
                        for(index in files) {
                            indexArr.push(index);
                        };
                        var iaLen = indexArr.length;
                        file = files[indexArr[iaLen - 1]];
                        for(var i = 0; i < iaLen - 1; i++) {
                            delete files[indexArr[i]];
                        }
                        try {
                            if(file.size > 200 * 1024) {
                                delete files[index];
                                photoCompress(file, {
                                    quality: 0.5,
                                }, function(base64Codes) {
                                    var bl = convertBase64UrlToBlob(base64Codes);
                                    obj.resetFile(index, bl, file.name);
                                    $("#btnHide").trigger("click");
                                });
                            } else {
                                $("#btnHide").trigger("click");
                            }
                        } catch(e) {
                            $("#btnHide").trigger("click");
                        }
                    },
                    done: function(res) {
                        //這裏把後臺返回的數據進行操做,展現上傳完成的圖片,具體數據格式參考layui的API
                    },
                    error: function() {

                    }
                });
            });

原理:在選擇照片以後,獲取文件,轉換爲blob對象,使用resetFile方法對文件列隊裏的文件進行從新設置,而後再觸發上傳事件。

踩的坑:

一、resetFile這個方法是layui 2.3.0 新增的,因此首先要確保layui的版本是最新的。

二、我把auto設置爲false,點擊btnHide時觸發上傳,我也試過自動上傳,自動上傳的話,這些操做的代碼就要寫在before方法中(具體看layui的API),然而我發現自動上傳修改文件列隊的方法老是在上傳成功以後才調用,這就致使實際上傳的圖片其實沒有壓縮,至於爲何是這個執行順序我隱約以爲是否是圖片轉碼,放入canvas的時候耽誤了……具體緣由我不明白,因此我用手動上傳,確認修改了文件列隊,再手動觸發上傳。

三、關於文件列隊,屢次上傳文件,文件列隊也就是obj.pushFile()返回的是多個文件的對象,並且這些文件對象的key仍是一串隨機數……因此個人思路是上傳一次,就用delete方法刪除隊列中已上傳過的文件。至於爲何不直接所有清空,由於考慮到不須要壓縮的狀況,若是所有清空,不壓縮,就沒有執行resetFile方法,文件列隊裏就沒有文件,會報錯。

相關文章
相關標籤/搜索