一、關於js上傳圖片壓縮的方法,百度有很多種方法,這里我參考修改了一下:
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對象。
注:因為牽扯到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部分:
$("#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是用來設置壓縮后圖片質量的,越小質量越差,表現出來就是圖片越模糊,但是相應的體積就越小。
最后使用formData.set(key,value,name)方法,將現有的name為file的表單元素的值改變。這個方法有三個參數,第一個是key值,也就是表單里對應的元素的name值(如果不存在會自行添加),第二個值是value值,第三個是選填的值,如果第二個值為blob對象或者file對象,則第三個值表示文件名。
當然,如果你不想用form表單提交,你也可以用ajax提交的方法:
html:
<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) {
}
});
});
三、結合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方法對文件列隊里的文件進行重新設置,然后再觸發上傳事件。
踩的坑:
1、resetFile這個方法是layui 2.3.0 新增的,所以首先要確保layui的版本是最新的。
2、我把auto設置為false,點擊btnHide時觸發上傳,我也試過自動上傳,自動上傳的話,這些操作的代碼就要寫在before方法中(具體看layui的API),然而我發現自動上傳修改文件列隊的方法總是在上傳成功之后才調用,這就導致實際上傳的圖片其實沒有壓縮,至於為什么是這個執行順序我隱約覺得是不是圖片轉碼,放入canvas的時候耽誤了……具體原因我不明白,所以我用手動上傳,確認修改了文件列隊,再手動觸發上傳。
3、關於文件列隊,多次上傳文件,文件列隊也就是obj.pushFile()返回的是多個文件的對象,而且這些文件對象的key還是一串隨機數……所以我的思路是上傳一次,就用delete方法刪除隊列中已上傳過的文件。至於為什么不直接全部清空,因為考慮到不需要壓縮的情況,如果全部清空,不壓縮,就沒有執行resetFile方法,文件列隊里就沒有文件,會報錯。
