Мультизагрузка файлов с progress bar

177
22 ноября 2018, 12:10

Мучает вопрос, как грамотно реализовать множественную загрузку файлов, чтобы при загрузке у каждого файла был свой progress bar.
Делал по примеру из статьи https://habr.com/post/109079
Изначально в инпут выбираем нужные файлы, затем при нажатии кнопки "загрузить", js прогоняет объект FileList на наличие выбранных в инпуте файлов и для каждого из них делает ajax запрос с отображением состояния файла, а на выходе сервер (испольую PHP) обрабатывает каждый файл по одному. Насколько эта реализация оправдана и есть ли другие способы реализовать подобное? (без использования сторонних плагинов).

$(document).ready(function(){ 
  $('#file-input').on('change', function(){ 
    var files = $(this).prop('files'); 
    $('#file-container').empty(); 
    for(var file of files) 
    { 
    //создаем превью из названия файла и програсс бара 
      var elem = $('<div class="file-previev"><p>'+file.name+'</p><progress class="file-progress" value="0" max="100"></progress></div>').appendTo($('#file-container')); 
      //добавляем к контейнеру с превью свойство файла для передачи 
      elem.get(0).fileInfo = file; 
    } 
  }); 
  $('#start').on('click', function(e){ 
    e.preventDefault(); 
    $('#file-container').find('.file-preview').each(function(){ 
      var file = this.file; 
      var progress = $(this).find('.file-progress'); 
      $.ajax({ 
        url: '/', 
        type: 'post', 
        contentType: false, 
        processData: false, 
        data: file, 
        xhr: function(){ 
          var xhr = $.ajaxSettings.xhr(); 
          xhr.upload.onprogress = function(evt){ 
            var percent = Math.ceil(evt.loaded/evt.total); 
            $(progress).attr('value', percent); 
          } 
        }, 
      }); 
    }); 
  }); 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
<form id="form-upload" method="post"> 
  <input id="file-input" type="file" multiple="true"/> 
  <button id="start" type="submit">Загрузить</button> 
</form> 
<div id="file-container"></div>

Собственно все подобные решения, которые я видел всегда подразумевают то, что на каждый файл посылается отдельный ajax запрос, который обрабатывает файл. Смущает этот момент, поскольку без реализации progress bar, просто собирают массив из инпут с именем file[] и в php работают с массивом файлов. А также не совсем понятно, как именно тут с помощью ajax передать файл в PHP и правильно его обработать, ибо видел разные реализации как в этом коде, так и с использованием объекта FormData.

Answer 1

Дошел до истины, как можно грамотно сделать мультизагрузку с прогресс баром:

$(document).ready(function() { 
  var input = $('#file-input'); 
  var button = $('#file-submit'); 
  var container = $('#file-container'); 
  input.on('change', function() { 
    var files = $(this).prop('files'); 
    for (var file of files) { 
      var elem = $('<div class="file-info"><p>' + file.name + '</p><progress class="progress-bar" max="100" value="0"></progress></div>').appendTo(container); 
      //добавляем инфу о файле в свойство превью 
      elem.get(0).file = file; 
    } 
  }); 
  //асинхронный колбек закачки файлов 
  button.on('click', async function(evt) { 
    evt.preventDefault(); 
    //пускаем закачку каждого файла параллельно с помощью Promise.all и дожидаемся закачки всех файлов с помощью await. 
    await Promise.all($('.file-info').map(upload)); 
    console.log('готово'); 
  }); 
 
  //асинхронная функция закачки файла 
  async function upload(index, elem) { 
    var data = new FormData(); 
    data.append('file', elem.file); 
    var progress = $(elem).find('.progress-bar'); 
    //ждем ответа об успешной обработке файла на стороне сервера 
    const res = await $.ajax({ 
      url: '/', 
      contentType: false, 
      processData: false, 
      data: data, 
      type: 'post', 
      xhr: function() { 
        var xhr = new XMLHttpRequest(); 
        xhr.upload.onprogress = function(evt) { 
          var percent = Math.ceil(evt.loaded / evt.total * 100); 
          progress.attr('value', percent); 
        } 
        return xhr; 
      } 
    }); 
  } 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
<form id="file-form" method="post"> 
  <input id="file-input" type="file" multiple> 
  <button id="file-submit" type="button">Отправить</button><br/> 
  <div id="file-container"></div> 
</form>

Примерно так я сделал решение с мультизагрузкой для себя. Разумеется этот код не идеален и его можно доработать проверками на тип, размер, отмену закачки и т.д.

READ ALSO
Создание таймера на страницах PHP и pagination

Создание таймера на страницах PHP и pagination

Задача в том, чтобы на всех страницах-слайдах разместить таймер времени и начиная с первой страницы включить этот таймер

258
Расспаристь &ldquo;тег&rdquo; игнорируя похожие

Расспаристь “тег” игнорируя похожие

В теле документа есть специальные теги в виде {name}, все бы хорошо, но есть конфликт, когда есть похожий тег {{name}}, где вместо одной фигурной скобки...

165
Cmake линковка на библиотеку подпроекта

Cmake линковка на библиотеку подпроекта

Имеется примерно следующий проект на Cmake:

148