it-roy-ru.com

HTML5 загрузка нескольких файлов: загрузка по одному через AJAX

У меня есть форма загрузки нескольких файлов:

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

Я публикую эти файлы с помощью ajax. Я хотел бы загрузить выбранные файлы по одному (для создания отдельных индикаторов выполнения и из любопытства).

Я могу получить список файлов или отдельных файлов по

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

Но FileList неизменен, и я не могу понять, как отправить один файл.

Я думаю, что это возможно, как я видел http://blueimp.github.com/jQuery-File-Upload/ . Однако я не хочу использовать этот плагин, так как он так же важен для обучения, как и результат (и в любом случае он будет слишком требовательным). Я также не хочу использовать Flash.

27
Mark

Чтобы это была синхронная операция, вам нужно начать новую передачу, когда последняя будет выполнена. Gmail, например, отправляет все сразу, одновременно. Событием для процесса загрузки файла AJAX является progress или onprogress в необработанном экземпляре XmlHttpRequest

Итак, после каждого $.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 
30
pocesar

Это похоже на очень хороший учебник, именно то, что вы ищете .

Тем не менее, загрузка через ajax Vanilla поддерживается не во всех браузерах, и я все равно рекомендую использовать iframe. (I.E динамически создает iframe и POST его использует javascript)

Я всегда использовал этот скрипт и я нахожу его очень лаконичным. Если вы хотите узнать, как загружать файлы с помощью создания iframe, вам следует изучить его исходные тексты.

Надеюсь, поможет :)

Дополнительное редактирование

Чтобы создать индикаторы выполнения с помощью метода iframe, вам нужно будет выполнить некоторые действия на стороне сервера. Если вы используете php, вы можете использовать:

Если вы используете nginx, вы также можете скомпилировать с их Загрузить модуль прогресса

Все они работают одинаково - каждая загрузка имеет UID, вы будете запрашивать «прогресс», связанный с этим идентификатором, через равные промежутки времени через ajax. Это вернет прогресс загрузки, определенный сервером.

8
Nathan Kot

Я столкнулся с той же проблемой и пришел с этим решением. Я просто извлекаю форму с помощью multipart и при рекурсивном вызове (файл за файлом) запускаю ajax-запрос, который вызывает следующий, только когда будет сделано.

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 );
    }
}
4
Jakub Hluchý

Используя этот исходный код, вы можете загрузить несколько файлов, таких как Google один за один через ajax. Также вы можете увидеть прогресс загрузки

HTML

 <input type="file" id="multiupload" name="uploadFiledd[]" multiple >
 <button type="button" id="upcvr" class="btn btn-primary">Start Upload</button>
 <div id="uploadsts"></div>

Javascript

<script>

function uploadajax(ttl,cl){

var fileList = $('#multiupload').prop("files");
$('#prog'+cl).removeClass('loading-prep').addClass('upload-image');

var form_data =  "";

form_data = new FormData();
form_data.append("upload_image", fileList[cl]);


var request = $.ajax({
          url: "upload.php",
          cache: false,
          contentType: false,
          processData: false,
          async: true,
          data: form_data,
          type: 'POST', 
          xhr: function() {  
      var xhr = $.ajaxSettings.xhr();
      if(xhr.upload){ 
        xhr.upload.addEventListener('progress', function(event){
                        var percent = 0;
                        if (event.lengthComputable) {
                            percent = Math.ceil(event.loaded / event.total * 100);
                        }
                        $('#prog'+cl).text(percent+'%')

                    }, false);
       }
      return xhr;
     }    
      })
      .success(function(res,status) {

        if(status == 'success'){

            percent = 0;
            $('#prog'+cl).text('');            

                $('#prog'+cl).text('--Success: ');

            if(cl < ttl){
                uploadajax(ttl,cl+1);
            }else{
               alert('Done ');

            }     

            }

      })
      .fail(function(res) {
      alert('Failed');
      });

}



$('#upcvr').click(function(){

var fileList = $('#multiupload').prop("files");
$('#uploadsts').html('');
var i
for ( i = 0; i < fileList.length; i++) {
$('#uploadsts').append('<p class="upload-page">'+fileList[i].name+'<span class="loading-prep" id="prog'+i+'"></span></p>');
if(i == fileList.length-1){
    uploadajax(fileList.length-1,0);
}
}

});

</script>

PHP

upload.php
    move_uploaded_file($_FILES["upload_image"]["tmp_name"],$_FILES["upload_image"]["name"]);
0
Milan Krushna