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

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

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

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

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

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

уступчивый

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.


person Mark    schedule 01.12.2012    source источник


Ответы (5)


Чтобы это была синхронная операция, вам нужно начать новую передачу, когда будет выполнена последняя. 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 
person pocesar    schedule 03.12.2012
comment
обратите внимание, что этот код предназначен для действительно современных браузеров, которые поддерживают только FormData и XmlHttpRequest2, никаких хаков для старых браузеров. - person pocesar; 04.12.2012
comment
Создание новой «формы» и добавление файлов один за другим с помощью (new FormData()).append('file', this.files[count]) было тем, что я искал, спасибо! - person Mark; 06.12.2012
comment
Согласен: где url? - person Richard Rodriguez; 20.03.2017
comment
Он использует тот же URL-адрес для почтового запроса. - person Soroush Falahati; 22.09.2017
comment
да, просто поместите все, что вам нужно, в свойство url, потому что при его опускании используется текущий URL-адрес. обратитесь к документации jQuery для этого api.jquery.com/jquery.ajax/# jQuery-ajax-настройки - person pocesar; 24.09.2017

Похоже, это очень хороший учебник, именно то, что вам нужно .

При этом загрузка через vanilla ajax поддерживается не во всех браузерах, и я бы по-прежнему рекомендовал использовать файл iframe. (IE динамически создает iframe и размещает его с помощью javascript)

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

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

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

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

Если вы используете nginx, вы также можете выполнить компиляцию с их модулем выполнения загрузки.

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

person Nathan Kot    schedule 03.12.2012
comment
Первая ссылка была действительно хорошим руководством по объектам FormData, спасибо! - person Mark; 06.12.2012

Я столкнулся с той же проблемой и пришел с этим решением. Я просто извлекаю форму с помощью 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 );
    }
}
person hluchjak    schedule 07.02.2015
comment
Это не то, что спросили. ОП попросил загрузить выбранные файлы один за другим с отдельными индикаторами выполнения. Проголосовали против. - person TheCarver; 06.07.2016

Используя этот исходный код, вы можете загружать несколько файлов, таких как 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"]);
person Milan Krushna    schedule 04.08.2018

HTML-код

<div class="row">
    <form id="singleUploadForm" name="singleUploadForm" style="float: right; padding-right: 25px">
        <input style="float: left;" id="singleFileUploadInput" type="file" name="files" class="file-input btn btn-default" required multiple/>
        <button style="float: left" type="submit" class="btn .btn-primary">Upload</button>
    </form>
</div>

Код JavaScript

$('#mutipleUploadForm').submit(function (event) {
    var formElement = this;
    var formData = new FormData(formElement);
    $.ajax({
        type: "POST",
        enctype: 'multipart/form-data',
        url: "/uploadFile",
        data: formData,
        processData: false,
        contentType: false,
        success: function (response) {
            alert("Image Uploaded Successfully");

            location.reload();
        },
        error: function (error) {
            console.log(error);
            // process error
        }
    });
    event.preventDefault();
});

Класс контроллера Spring

@PostMapping("/uploadFile")
@ResponseBody
public boolean uploadMutipleFiles(@RequestParam("file") MultipartFile[] file) {
    List<Boolean> uploadStatusList = new ArrayList<>();
    for (MultipartFile f : file) {
        uploadStatusList.add(uploadFile(f));
    }
    return !uploadStatusList.contains(false);
}

public boolean uploadFile(@RequestParam("file") MultipartFile file) {
    boolean uploadStatus = galleryService.storeFile(file);
    return uploadStatus;
}

Весенний класс обслуживания

public boolean storeFile(MultipartFile file) {
    boolean uploadStatus = false;
    try {
        String fileName = file.getOriginalFilename();
        InputStream is = file.getInputStream();
        Files.copy(is, Paths.get(imagesDirectory + fileName), StandardCopyOption.REPLACE_EXISTING);
        System.out.println("File store success");
        uploadStatus = true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return uploadStatus;
}
person Shreyas    schedule 11.10.2019