總結:ajax多檔案上傳,帶進度條,前端篇
前言:
之前寫過一個檔案上傳的模組,但是是多個input上傳的,而且使用的是jQuery.form打包上傳的,這樣子就覺得還是有點不太方便。
1.提交的時候需要將整個form提交上去,換句話說就是需要將要提交的內容使用form將內容包括起來
2. 檔案input雖然可以在頁面上設定增減功能的辦法調整檔案數量,但是一般會設定上限(例如最多新增10個input,不然太多了頁面就太亂了,當然這個情況在大部分情況下不是什麼大問題,只有在要上傳大量零散檔案的時候才算有問題)
——————————————————————下面是我改進的方法———————————————————————
html:
<div class="input-group">
<input type="file" id="attachment" multiple>
<span id="progress_bar" style="color: #1AB394;display: table-cell"></span>
</div>
<ul id="attachment_list"></ul>
<button class="btn btn-file">upload file</button>
html中,只有input是主要的,其他的元素都可以按照需要替換掉。
js:
$.ajaxSetup({ //laravel中的request要帶這個header引數
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$('.btn-file').click(function(){
if($('#attachment').val() == '')
alert('請選擇檔案再上傳' );
else{
var path = $('#attachment')[0].files;
var formData = new FormData();
var names = '';
/*
提示:FormData不能寫陣列,array json都不行,能寫簡單的key->value鍵值對。
鍵值對中key不能是中文,不然後臺讀不出來,而且要保證key的唯一性,
那麼我就用檔名path[i].name用md5加密一下好了,當然你也可以用自己喜歡的加密方式。
因為laravel不能便利地讀取所有file,只能用file('key')讀取key值的value,
是的,所以你不知道key值是讀不出你要的東西的。因為檔案的key是變化的,所以我這裡寫定一個info欄位,
然後把檔案的key寫成字串,然後後臺解析字串,再根據裡面的欄位獲取檔案。
你也可以寫其他需要的資料的鍵值對到FormData裡面,一併傳到後臺,當成一個虛擬form表單用就行了。
/*
for(var i= 0,name;i<path.length;i++){
name = $.md5(path[i].name);
formData.append(name, path[i]);
names += name + ',';
}
formData.append('info',names);
$.ajax({
url: "{{route('upload')}}",
type: 'POST',
cache: false,
data: formData,
processData: false,
contentType: false,
beforeSend: function(){
$('#progress_bar').css('color','#1AB394').show();
},
success: function(result
{
$('#progress_bar').html(result.info).css('color','black').fadeOut(3000,function(){$(this).html('')});
},
error: function (result) {
},
xhr: function(){
var xhr = $.ajaxSettings.xhr();
if(onprogress && xhr.upload) {
xhr.upload.addEventListener("progress" , onprogress, false);
return xhr;
}
}
});
/*
小tips:在網上查詢遇到一些方法(例如function A()),沒有詳細介紹,不知道總共完整傳多少個引數,
每個引數長什麼樣子的,可以寫成function A(a,b,c,d,e,…………){//然後寫log打印出來},
這裡只有一個event物件引數,所以我寫4個形參上去,然後寫日誌出來,只有第一個引數寫出來是一個物件,
而且裡面有什麼屬性也會寫出來,後面3個形參則輸出為空,
那麼這時候就能寫定 function A(obj){//只有一個引數,自己寫個喜歡的形參名}。
前端後臺都能用這個小技巧哦~
*/
function onprogress(evt){
console.log(evt);
var loaded = evt.loaded;
var tot = evt.total;
$('#progress_bar').html(Math.floor(100*loaded/tot)+'%');
}
這裡的js是用一個FormData物件,將資料填充進去,然後偽裝成從form裡提取的資料(意思大概是這個意思吧~),如果要上傳檔案,那麼和普通的ajax傳資料的引數有些不同,可以按照我上面寫的設定引數,ajax具體引數有什麼作用可以看我這個blog:http://blog.csdn.net/qq_29238009/article/details/77506048。
因為原生ajax是有進度的引數的,progress還是什麼來著,但是jQuery是封裝了原生ajax物件的一種物件,是沒有設定這個引數的,所以不能像success、error這樣直接寫函式。但是jQuery有個引數xhr能夠返回原生ajax物件,然後通過原生ajax物件進行進度條的操作,如上ajax寫好xhr以及它所呼叫的onprogress函式,就能獲取ajax上傳的資料進度了。
寫好前後臺後上傳大概就是這個效果了。
input的檔案改變的時候寫一下ul列表,然後上傳的時候寫一下進度百分比。當然這些都是可以按需調整的,我這裡簡單寫寫,可以設計一下寫的更漂亮豐富,加多點特效,寫成進度條之類的,也可以刪減不要
後臺我寫過一個blog,因為前端是js,但是後臺可以是不同語言,我這裡用的後臺是laravel框架,用php寫的,如果你是用其他語言寫的後臺,可以自己寫過一個後臺適配這個前端。反正就是ajax傳一些檔案和欄位到後臺而已,接收好就行了,該怎麼處理看自己的業務邏輯需要怎麼做吧。
已知缺陷:
1. 和我前言說的那種N個檔案用N個input相比,這樣的多選上傳只能選中同一級目錄下的檔案(當然這個也是能解決的,因為FormData能模擬表單,所以你可以在頁面上隨意不同位置寫上input然後填充進FormData裡面,同樣不用form標籤包裹住,也能顯示上傳進度。總的來說,要上傳N個級目錄下的檔案,就要有N個input,同一級目錄上傳檔案就一個input可以了)