2012-12-01 44 views
24

Tôi có một nhiều file upload hình thức:HTML5 nhiều tập tin tải lên: tải lên từng người một qua AJAX

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

Tôi đăng những tập tin này với ajax. Tôi muốn tải lên các tập tin được chọn từng người một (để tạo ra các thanh tiến trình cá nhân, và ra khỏi tò mò).

Tôi có thể lấy danh sách các tập tin hoặc các tập tin cá nhân bằng cách

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...} 

Nhưng FileList là không thay đổi và tôi không thể tìm ra cách để nộp hồ sơ duy nhất.

Tôi nghĩ rằng điều này là có thể như tôi đã thấy http://blueimp.github.com/jQuery-File-Upload/. Tôi không muốn sử dụng plugin này tuy nhiên vì nó là càng nhiều về học tập như là kết quả (và nó sẽ cần quá nhiều custimizing anyway). Tôi cũng không muốn sử dụng Flash.

Trả lời

26

Để đây là thao tác đồng bộ, bạn cần bắt đầu quá trình chuyển mới khi thao tác cuối cùng được thực hiện. Gmail, ví dụ, gửi tất cả mọi thứ cùng một lúc, đồng thời. Sự kiện cho tiến trình tải lên tệp AJAX là progress hoặc onprogress trên phiên bản XmlHttpRequest thô.

Vì vậy, sau mỗi $.ajax(), ở phía máy chủ (mà tôi không biết bạn sẽ sử dụng cái gì), hãy gửi phản hồi JSON để thực thi AJAX trên đầu vào tiếp theo. Một tùy chọn sẽ liên kết phần tử AJAX với từng phần tử, để làm cho mọi thứ trở nên dễ dàng hơn, vì vậy bạn có thể thực hiện, trong success số $(this).sibling('input').execute_ajax().

Something như thế này:

$('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 

Đoạn mã trên sẽ cho nhiều <input type="file"> nhưng không phải cho <input type="file" multiple>, trong trường hợp đó, nó phải là:

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

lưu ý rằng mã này được thiết kế cho các trình duyệt thực sự hiện đại hỗ trợ FormData và XMLHttpRequest2 chỉ, không có hacks cho các trình duyệt cũ – pocesar

+4

Đã tự hỏi tại sao nó trông rất ngon ...;) – Selosindis

+5

Tạo một 'hình thức' mới và thêm tập tin từng người một bằng cách sử dụng '(new FormData()). append ('file', this.files [count])' là những gì tôi đang tìm kiếm, cảm ơn! – Mark

7

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

Lưu ý rằng việc tải lên qua vanilla ajax không được hỗ trợ trong tất cả các trình duyệt và tôi vẫn khuyên bạn nên sử dụng iframe. (I.E tự động tạo iframe và POST bằng iframe)

I have always been using this script và tôi thấy nó rất súc tích. Nếu bạn muốn tìm hiểu cách tải lên thông qua tạo iframe, bạn nên tìm hiểu kỹ nguồn của nó.

Hy vọng nó sẽ giúp :)

tắm chỉnh sửa

Để tạo thanh tiến với phương pháp iframe, bạn sẽ cần phải làm một số công việc server-side. Nếu bạn đang sử dụng php, bạn có thể sử dụng:

Nếu sử dụng nginx bạn cũng có thể chọn để biên dịch với họ Upload progress module

Tất cả những hoạt động theo cùng một cách - mỗi lần tải lên có một UID, bạn sẽ yêu cầu cho 'tiến bộ' kết hơp với ID tại khoảng thời gian nhất quán qua ajax. Điều này sẽ trả về tiến độ tải lên như được xác định bởi máy chủ.

+0

Liên kết đầu tiên thực sự là một hướng dẫn tốt về các đối tượng FormData, cảm ơn! – Mark

1

Tôi đã gặp phải sự cố tương tự và đi kèm với giải pháp này. Tôi chỉ đơn giản là lấy mẫu với multipart, và trong cuộc gọi đệ quy (tập tin sau khi tập tin) bắt đầu yêu cầu ajax, mà chỉ gọi tiếp theo khi được thực hiện.

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

Đây không phải là những gì được hỏi. OP yêu cầu tải lên các tệp đã chọn từng người một với các thanh tiến trình riêng lẻ. Đã bỏ phiếu. – TheCarver

Các vấn đề liên quan