起源
我之前一直做的是單圖上傳,或者單圖上傳加預(yù)覽的模式拔恰,實現(xiàn)起來都不是那么麻煩,下面都會提到基括。
而今天給自己挖了個坑颜懊,批量上傳多張圖片,類似這樣:
然后我還特想裝13风皿,想研究下原理河爹。
從頭說這件事
文件上傳,html的基礎(chǔ)表單組件就提供了該功能的實現(xiàn)桐款,使用非常簡單的表單提交就能做咸这。然而可能一些pm覺得圖片能實時預(yù)覽是非常好的用戶體驗,這時候可以用js來構(gòu)建form表單異步上傳魔眨。再往后推媳维,就要求既能批量上傳酿雪,又能實時預(yù)覽。說白了感覺用戶體驗什么的借口感覺都是在挖坑給我們寫代碼的侄刽。
cp1 表單上傳
代碼優(yōu)先發(fā)言:
<form action="index.php" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="提交">
</form>
效果圖發(fā)言:
這個體驗確實不好指黎,只有文件名,沒有文件的內(nèi)容預(yù)覽州丹。
后端代碼貼個servlet3的
先把servlet加上 <code>@MultipartConfig(maxFileSize=1024x1024x10)</code> 注解醋安,然后邏輯代碼如下:
Part part=request.getPart("file");
if (null!=part&&part.getSize()>0) {
InputStream inputStream=part.getInputStream();
ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
byte[] buffer = new byte[1024*100];
int len=0;
while ((len=inputStream.read(buffer,0,buffer.length))>0) {
outputStream.write(buffer,0,len);
}
byte[] fileByte=outputStream.toByteArray();
}
拿到byte數(shù)組后面的操作代碼我就不貼了,有的存本地文件墓毒,有的上傳到文件服務(wù)器吓揪,這個因項目架構(gòu)而定,反正servlet3的后端邏輯差不多就是這樣所计,至于使用其他框架的自行查詢對照實現(xiàn)柠辞。
cp2 異步上傳預(yù)覽
效果圖優(yōu)先發(fā)言:
這里我使用 jquery 的 fileupload 實現(xiàn)的,當然也有很多極簡愛好者自己實現(xiàn)醉箕,原理也很簡單钾腺。
前端代碼,跟上面結(jié)構(gòu)一致
<form action="index.php" method="post" enctype="multipart/form-data">
<input id="selectFile" type="file" name="file">
<input type="submit" value="提交">
</form>
js代碼
$("#selectFile").fileupload({
dataType: "json",
url: "/upload/singleFile",
type: "POST",
done: function(e, data) {
$("#selectFile").before('<img src="'+data.result.result+'"/>');
}
});
這里文件選擇好后直接上傳到后臺讥裤,上傳完成后插入一個img標簽做預(yù)覽效果放棒。文件的上傳和表單的提交是分開的!表單提交的時候只提交文件的編號或者地址己英,不包含任何文件间螟。
使用框架的好處就是簡單方便,缺點是不了解原理损肛,高級特性沒辦法用厢破。
異步上傳文件的原理是,構(gòu)造一個iframe進行上傳治拿,上傳完成后獲取iframe的內(nèi)容摩泪,作為服務(wù)器的返回結(jié)果,前端拿到返回的結(jié)果后劫谅,構(gòu)造img展示預(yù)覽圖见坑。(這里本來要配代碼,無奈之前收藏的書簽丟失了捏检,不過不重要荞驴,后面有更簡單的方式)
cp3 批量上傳并預(yù)覽
雖然前面提到的 jquery 的 fileupload 插件能實現(xiàn),但是作為一名極簡主義者贯城,自然是要自熊楼!己!開能犯!發(fā)鲫骗!
前端代碼犬耻,input加入multiple屬性
<form action="index.php" method="post" enctype="multipart/form-data">
<input id="selectFile" type="file" name="file" multiple="multiple">
<input type="submit" value="提交">
</form>
js代碼:
因為坑挖的奇葩,需要在圖片上傳之前做一些前置操作挎峦,拿到選擇圖片的信息:
var files=$("#selectFile")[0].files;
for (var i = 0; i < files.length; i++) {
var file=files[i];
console.log(file);
}
看下打印出來的信息
lastModified:1471099234297
lastModifiedDate:Sat Aug 13 2016 22:40:34 GMT+0800 (中國標準時間)
name:"6.png"
size:26476
type:"image/png"
webkitRelativePath:""
不錯香追,圖片類型,大小坦胶,圖片名都顯示出來了透典,要做前置操作的在這里做抓緊做。
那么我們拿到文件的dom了怎么上傳顿苇?當是我是懵逼的峭咒,因為文件上傳,包括插件纪岁,單位都是 input 凑队,這是input 里面的東西,怎么上傳幔翰?
后來找到了一種方法漩氨,XMLHttpRequest,構(gòu)造請求提交表單遗增。構(gòu)叫惊!造!請做修!求霍狰!這不是類似java的HttpClient嗎?萬能的工具饰及!
核心代碼:
var xhr = new XMLHttpRequest();
xhr.open('POST', "index.php", true);
var formData = new FormData();
formData.append('file', file); // file 為上面拿到的file對象
xhr.onreadystatechange = function(response) { // 文件上傳完畢通知函數(shù)
console.log(xhr.responseText)蔗坯;
}
xhr.send(formData);
具體的實現(xiàn)參照前面cp2就能實現(xiàn),這里篇幅有限燎含,不多闡述宾濒。
結(jié)語
有時候js的原理確實該看看,反正又不難屏箍,半天的時間就能搞定绘梦。
愿每位碼農(nóng)都能在天梯上披襟斬棘,一統(tǒng)逼界铣除,千秋萬載。