1. 程式人生 > >總結:ajax多檔案上傳,帶進度條,前端篇

總結: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可以了)