2012-12-01 105 views
24

上傳逐一我有多個文件上傳表單:HTML5多文件上傳:通過AJAX

<input type="file" name="files" multiple /> 

我張貼阿賈克斯這些文件。我想逐個上傳選定的文件(創建單個進度條,並出於好奇)。

我可以

FL = form.find('[type="file"]')[0].files 
F = form.find('[type="file"]')[0].files[0] 

yieling

FileList { 0=File, 1=File, length=2 } 
File { size=177676, type="image/jpeg", name="img.jpg", more...} 

獲取文件或單個文件的列表中,但文件清單是不可改變的,我無法弄清楚如何提交單個文件。

我認爲這是可能的,因爲我看到http://blueimp.github.com/jQuery-File-Upload/。但是我不想使用這個插件,因爲它和學習的結果一樣多(並且無論如何它需要太多的自定義)。我也不想使用Flash。

回答

26

對於這是一個同步操作,您需要在最後一個完成,開始新的傳遞。例如,Gmail可以同時發送所有內容。 對AJAX的文件上傳進度的事件是對原始XmlHttpRequest實例progressonprogress

因此,在每個$.ajax()之後,在服務器端(我不知道你將使用什麼),發送一個JSON響應來在下一個輸入上執行AJAX。一種選擇是對AJAX元素結合到每一個元素,使事情變得更容易,所以你可以只執行,在success$(this).sibling('input').execute_ajax()

事情是這樣的:

$('input[type="file"]').on('ajax', function(){ 
    var $this = $(this); 
    $.ajax({ 
    'type':'POST', 
    'data': (new FormData()).append('file', this.files[0]), 
    'contentType': false, 
    'processData': false, 
    'xhr': function() { 
     var xhr = $.ajaxSettings.xhr(); 
     if(xhr.upload){ 
     xhr.upload.addEventListener('progress', progressbar, false); 
     } 
     return xhr; 
    }, 
    'success': function(){ 
     $this.siblings('input[type="file"]:eq(0)').trigger('ajax'); 
     $this.remove(); // remove the field so the next call won't resend the same field 
    } 
    }); 
}).trigger('ajax'); // Execute only the first input[multiple] AJAX, we aren't using $.each 

上面的代碼將是多個<input type="file">而不是<input type="file" multiple>,在這種情況下,它應該是:

var count = 0; 

$('input[type="file"]').on('ajax', function(){ 
    var $this = $(this); 
    if (typeof this.files[count] === 'undefined') { return false; } 

    $.ajax({ 
    'type':'POST', 
    'data': (new FormData()).append('file', this.files[count]), 
    'contentType': false, 
    'processData': false, 
    'xhr': function() { 
     var xhr = $.ajaxSettings.xhr(); 
     if(xhr.upload){ 
     xhr.upload.addEventListener('progress', progressbar, false); 
     } 
     return xhr; 
    }, 
    'success': function(){ 
     count++; 
     $this.trigger('ajax'); 
    } 
    }); 
}).trigger('ajax'); // Execute only the first input[multiple] AJAX, we aren't using $.each 
+4

注意,此代碼是用於支持FORMDATA和XMLHttpRequest2中唯一的,舊的瀏覽器 – pocesar

+4

沒有黑客不知道爲什麼它看起來那麼好吃......真是的現代瀏覽器;) – Selosindis

+5

創建一個新的「形式」,並加入使用'(新的FormData())。append('file',this.files [count])''一個接一個的文件是我一直在尋找的,謝謝! – Mark

7

This looks like a very good tutorial, just what you're looking for

也指出,通過香草AJAX上傳所有的瀏覽器不支持,我仍然會建議使用iframe。 (即動態地創建一個iframe,使用JavaScript張貼)

I have always been using this script,我覺得它非常簡潔。如果你想學習如何通過創建一個iframe來上傳,你應該挖掘它的源代碼。

希望它能幫助:)

額外的編輯與iframe的方法

要創建進度條,你需要做一些工作的服務器端。如果你正在使用PHP,你可以使用:

如果使用nginx的你也可以選擇與自己Upload progress module

所有這些工作,以同樣的方式編譯 - 每次上傳了一個UID,你會要求與該ID在相關的「進步」通過ajax保持一致的間隔。這將返回由服務器確定的上載進度。

+0

第一個鏈接的確是一個關於FormData對象的好教程,謝謝! – Mark

1

我面臨同樣的問題,並與此解決方案。我只是用multipart檢索表單,並在遞歸調用(file after file)時啓動ajax請求,只有在完成時才調用next。

var form = document.getElementById("uploadForm"); 
var fileSelect = document.getElementById("photos"); 
var uploadDiv = document.getElementById("uploads"); 

form.onsubmit = function(event) { 
    event.preventDefault(); 

    var files = fileSelect.files; 
    handleFile(files, 0); 
}; 

function handleFile(files, index) { 
    if(files.length > index) { 
     var formData = new FormData(); 
     var request = new XMLHttpRequest(); 

     formData.append('photo', files[ index ]); 
     formData.append('serial', index); 
     formData.append('upload_submit', true); 

     request.open('POST', 'scripts/upload_script.php', true); 
     request.onload = function() { 
      if (request.status === 200) { 
       console.log("Uploaded"); 
       uploadDiv.innerHTML += files[ index ].name + "<br>"; 
       handleFile(files, ++index); 
      } else { 
       console.log("Error"); 
      } 
     }; 
     request.send(formData); 
    } 
} 
+0

這不是問了什麼。 OP要求用單獨的進度條一個接一個地上傳選定的文件。 Downvoted。 – TheCarver