JS移動(dòng)端/H5同時(shí)選擇多張圖片上傳并使用canvas壓縮圖片
最近在做一個(gè)H5的項(xiàng)目,里邊涉及到拍照上傳圖片的功能以及識(shí)別圖片的功能,這里對(duì)識(shí)別圖片的功能不做贅述,不屬本文范疇。我在做完并上線項(xiàng)目后,同事跟我提了一個(gè)要求是可不可以同時(shí)選擇多張圖片上傳,我做的時(shí)候的想法是如果給file表單加了 multiple 屬性就沒有辦法調(diào)用手機(jī)的攝像頭拍照了,如果不加,就無(wú)法同時(shí)選擇多張圖片,于是我就照實(shí)跟同事說(shuō)了這個(gè)情況。但回頭一想,單張圖片可以上傳,那多張圖片呢?于是就有了本文的內(nèi)容。
HTML5定義了 FileReader 作為文件 API 的重要成員用于讀取文件,根據(jù) W3C 的定義,F(xiàn)ileReader接口提供了讀取文件的方法和包含讀取結(jié)果的事件模型。
FileReader的實(shí)例擁有 4 個(gè)方法,其中 3 個(gè)用以讀取文件,另一個(gè)用來(lái)中斷讀取。下面的表格列出了這些方法以及他們的參數(shù)和功能,需要注意的是 ,無(wú)論讀取成功或失敗,方法并不會(huì)返回讀取結(jié)果,這一結(jié)果存儲(chǔ)在 result 屬性中。
| 方法名 | 參數(shù) | 描述 |
|---|---|---|
| abort | none | 中斷讀取 |
| readAsBinaryString | file | 將文件讀取為二進(jìn)制碼 |
| readAsDataURL | file | 將文件讀取為 DataURL |
| readAsText | file, [encoding] | 將文件讀取為文本 |
readAsText:該方法有兩個(gè)參數(shù),其中第二個(gè)參數(shù)是文本的編碼方式,默認(rèn)值為 UTF-8。這個(gè)方法非常容易理解,將文件以文本方式讀取,讀取的結(jié)果即是這個(gè)文本文件中的內(nèi)容。
readAsBinaryString:該方法將文件讀取為二進(jìn)制字符串,通常我們將它傳送到后端,后端可以通過(guò)這段字符串存儲(chǔ)文件。
readAsDataURL:這是例子程序中用到的方法,該方法將文件讀取為一段以 data: 開頭的字符串,這段字符串的實(shí)質(zhì)就是 Data URL,Data URL是一種將小文件直接嵌入文檔的方案。這里的小文件通常是指圖像與 html 等格式的文件。
FileReader還包含了一套完整的事件模型,用于捕獲讀取文件時(shí)的狀態(tài),下面這個(gè)表格歸納了這些事件。
| 事件 | 描述 |
|---|---|
| onabort | 中斷時(shí)觸發(fā) |
| onerror | 出錯(cuò)時(shí)觸發(fā) |
| onload | 文件讀取成功完成時(shí)觸發(fā) |
| onloadend | 讀取完成觸發(fā),無(wú)論成功或失敗 |
| onloadstart | 讀取開始時(shí)觸發(fā) |
| onprogress | 讀取中 |
文件一旦開始讀取,無(wú)論成功或失敗,實(shí)例的 result 屬性都會(huì)被填充。如果讀取失敗,則 result 的值為 null ,否則即是讀取的結(jié)果,絕大多數(shù)的程序都會(huì)在成功讀取文件的時(shí)候,抓取這個(gè)值。
了解了H5提供的 FileReader 后,我們就使用 FileReader 來(lái)實(shí)現(xiàn)同事選擇多張圖片并上傳。
首先,在 HTML 加入一個(gè)file表單,并設(shè)置其為 multiple(瀏覽器在對(duì)multiple、disabled、checked、selected等這類屬性進(jìn)行解析時(shí),只要這些屬性存在,默認(rèn)的就會(huì)被解析成true,甭管你設(shè)置的是disabled=true或者disabled=false亦或是disabled="",如果不想這些屬性起作用,唯有用js來(lái)remove掉這些屬性,除非你不設(shè)置這些屬性。),并設(shè)置accept="image/*"用以只能選擇圖片類型的文件,代碼如下:
<input type="file" accept="image/*" name="upload" id="upload" multiple> <input type="hidden" id="hiddenImgUrl" /> <!--設(shè)置這個(gè)隱藏域是為了便于存放上傳至服務(wù)器后返回的圖片地址-->
接下來(lái)就到了js上場(chǎng)了:
//圖片上傳
var file = {
upload: function (e) {
var self = this;
var files = e.target.files;
var type = files[0].type.split('/')[0];
if (type != 'image') {
alertMsg('請(qǐng)上傳圖片');
return;
}
//var size = Math.floor(file.size / 1024 / 1024);
//if (size > 3) {
// alert('圖片大小不得超過(guò)3M');
// return;
//};
for (var i = 0; i < files.length; i++) {
var reader = new FileReader();
reader.readAsDataURL(files[i]);
reader.onloadstart = function () {
//用以在上傳前加入一些事件或效果,如載入中...的動(dòng)畫效果
};
reader.onloadend = function (e) {
var dataURL = this.result;
var imaged = new Image();
imaged.src = dataURL;
imaged.onload = function () { //利用canvas對(duì)圖片進(jìn)行壓縮
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var w = 0;
var h = 0;
if (this.width > this.height) {
h = 1000;
var scale = this.width / this.height;
h = h > this.height ? this.height : h;
w = h * scale;
}
else {
w = 1000;
var scale = this.width / this.height;
w = w > this.width ? this.width : w
h = w / scale;
}
var anw = document.createAttribute("width");
var anh = document.createAttribute("height");
if (this.width > this.height) {
anw.value = h;
anh.value = w;
}
else {
anw.value = w;
anh.value = h;
}
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh);
if (this.width > this.height) {
ctx.translate(h, 0);
ctx.rotate(90 * Math.PI / 180)
ctx.drawImage(this, 0, 0, w, h);
ctx.restore();
}
else {
ctx.drawImage(this, 0, 0, w, h);
}
dataURL = canvas.toDataURL('image/jpeg');
//回調(diào)函數(shù)用以向數(shù)據(jù)庫(kù)提交數(shù)據(jù)
self.callback(dataURL);
};
};
}
},
event: function () {
$("#upload").change(function (e) {
file.upload(e);
});
},
callback: function (dataURL) {
$.ajaxSettings.async = false; //這里必須將ajax的異步改為同步才可以把返回并保存在隱藏域中的圖片地址取出同時(shí)加在地址欄中作為參數(shù)一并傳入下一個(gè)頁(yè)面,這樣做的目的是因?yàn)榉祷氐膱D片地址不是一個(gè)json數(shù)組,而是單個(gè)的json字符串,所以只能將返回的圖片地址json字符串拼接在一起作為參數(shù)傳到下一個(gè)頁(yè)面
$.post(url, dataURL, function (res) { //將base64圖片流的圖片通過(guò)后臺(tái)轉(zhuǎn)換成普通的圖片路徑并上傳至服務(wù)器
var imgUrl = $("#hiddenImgUrl").val();
if (res.success) {
$(".loading").hide();
if (imgUrl != "") {
$("#hiddenImgUrl").val(imgUrl + "|" + res.imgUrl); //中間加一個(gè) | 是為了到下一個(gè)頁(yè)面便于將傳過(guò)去的圖片地址參數(shù)轉(zhuǎn)換為數(shù)組
} else {
$("#hiddenImgUrl").val(res.imgUrl);
}
var imgUrl = $("#hiddenImgUrl").val();
window.location.href = "apply.html?imgUrl=" + imgUrl;
} else {
alert(res.message);
}
}, "json");
},
init: function () {
this.event();
}
}
file.init();
由于在通過(guò)post向服務(wù)器上傳時(shí)采用了同步的方式,所以我在寫項(xiàng)目的過(guò)程中,老是無(wú)法實(shí)現(xiàn)加載中的動(dòng)畫效果,并且把加載中的動(dòng)畫效果放在 reader.onloadstart方法中依舊不起作用,最后只能放在了$("#upload").change(function (e) {})方法中,代碼如下:
event: function () {
$("#upload").change(function (e) {
$(".loading").show();
file.upload(e);
});
}
以上是同時(shí)上傳多張圖片并將圖片傳入下一個(gè)頁(yè)面繼續(xù)進(jìn)行后續(xù)操作,那么如何在同時(shí)上傳完多張圖片后在本頁(yè)再預(yù)覽這些圖片呢?其實(shí)方法也是很簡(jiǎn)單的,上邊callback函數(shù)里邊的$.post的返回值里就包含了上傳至服務(wù)器后的圖片路徑,將這些路徑賦給img標(biāo)簽的src,然后再插入到頁(yè)面中就OK了,代碼如下:
callback: function (dataURL) {
$.post(url, dataURL, function (res) { //將base64圖片流的圖片通過(guò)后臺(tái)轉(zhuǎn)換成普通的圖片路徑并上傳至服務(wù)器
if (res.success) {
$(".loading").hide();
var result = '<div class="result"><img src="'+res.imgUrl+'" alt=""/></div>';
var div = document.createElement('div');
div.innerHTML = result;
document.body.appendChild(div);
} else {
alert(res.message);
}
}, "json");
}
以上在預(yù)覽圖片時(shí)由于不需要跳轉(zhuǎn),不需要傳入返回的所有圖片的路徑作為參數(shù),所以也就不需要將ajax的異步設(shè)置為同步了。
以上所述是小編給大家介紹的JS移動(dòng)端/H5同時(shí)選擇多張圖片上傳并使用canvas壓縮圖片,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
詳解處理bootstrap4不支持遠(yuǎn)程靜態(tài)框問題
這篇文章主要介紹了詳解處理bootstrap4不支持遠(yuǎn)程靜態(tài)框問題,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
原生javascript單例模式的應(yīng)用實(shí)例分析
這篇文章主要介紹了原生javascript單例模式的應(yīng)用,結(jié)合實(shí)例形式分析了JavaScript單例模式的基本功能、原理、應(yīng)用及操作注意事項(xiàng),需要的朋友可以參考下2020-02-02
jquery中l(wèi)ive()方法和bind()方法區(qū)別分析
這篇文章主要介紹了jquery中l(wèi)ive()方法和bind()方法區(qū)別,結(jié)合實(shí)例形式簡(jiǎn)單分析了live()方法和bind()方法的功能、使用方法與用法區(qū)別,需要的朋友可以參考下2016-06-06
優(yōu)雅的使用javascript遞歸畫一棵結(jié)構(gòu)樹示例代碼
這篇文章主要給大家介紹了關(guān)于如何優(yōu)雅的使用javascript遞歸畫一棵結(jié)構(gòu)樹的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用javascript具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
JavaScript & jQuery完美判斷圖片是否加載完畢
本文主要介紹了JavaScript & jQuery完美判斷圖片是否加載完畢的方法。具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-01-01
判斷JavaScript中的兩個(gè)變量是否相等的操作符
可能有些同學(xué)看到這個(gè)標(biāo)題就會(huì)產(chǎn)生疑惑,為什么我們要判斷JavaScript中的兩個(gè)變量是否相等,JavaScript不是已經(jīng)提供了雙等號(hào)“==”以及三等號(hào)“===”給我們使用了嗎2019-12-12

