Создайте несколько элементов input type=file с их соответствующим значением (FileList) в соответствии с основным элементом input type=file (несколько)

У меня есть этот код, где я зацикливаюсь на файлах из нескольких типов входных файлов

$(function(){

$('#main-input').change(function(){
  var files = $('#main-input')[0].files;
  for (var i = 0, f; f = files[i]; i++) {

      alert(files[i].name);

  }
});

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" id="main-input" multiple>

Чего я пытаюсь добиться, так это клонировать основной ввод (#main-input) и дает значение (файл) на основе файлов цикла. Любые идеи, предложения, пожалуйста? или это вообще возможно?


person Juliver Galleto    schedule 15.01.2018    source источник


Ответы (1)


Да, требование возможно. Вам нужно будет создать новый FileList для каждого объекта File, а затем установить свойство .files элемента <input type="file"> на FileList, заполненное объектом File.

Код ниже возвращает те же результаты в Chromium 62+ и Firefox 57+, см. комментарии @Kaiido для оценок по адресу Safari и Edge.

// FileList.js
class FileList {
  constructor(...items) {
    // flatten rest parameter
    items = [].concat(...items);
    // check if every element of array is an instance of `File`
    if (items.length && !items.every(file => file instanceof File)) {
      throw new TypeError("expected argument to FileList is File or array of File objects");
    }
    // use `ClipboardEvent("").clipboardData` for Firefox, which returns `null` at Chromium
    // we just need the `DataTransfer` instance referenced by `.clipboardData`
    const dt = new ClipboardEvent("").clipboardData || new DataTransfer();
    // add `File` objects to `DataTransfer` `.items`
    for (let file of items) {
      dt.items.add(file)
    }
    return dt.files;
  }
}

document.querySelector("input[type=file]")
.onchange = e => {
  for (let file of e.target.files) {
    const input = document.createElement("input");
    input.type = "file";
    input.files = new FileList(file);
    document.body.appendChild(input);
  }
}
<input type="file" multiple>

// FileList.js
function _FileList(items) {
    // flatten rest parameter
    items = [].concat.apply([], [items]);
    // check if every element of array is an instance of `File`
    if (items.length 
        && !items.every(function(file) { 
             return file instanceof File})) {
      throw new TypeError("expected argument to FileList is File or array of File objects");
    }
    // use `ClipboardEvent("").clipboardData` for Firefox, which returns `null` at Chromium
    // we just need the `DataTransfer` instance referenced by `.clipboardData`
    var dt = new ClipboardEvent("").clipboardData || new DataTransfer();
    // add `File` objects to `DataTransfer` `.items`
    for (var i = 0; i < items.length; i++) {
      dt.items.add(items[i])
    }
    return dt.files;
}

document.querySelector("input[type=file]")
.onchange = function(e) {
  for (var i = 0; i < e.target.files.length; i++) {
    var input = document.createElement("input");
    input.type = "file";
    input.files = new _FileList(e.target.files[i]);
    document.body.appendChild(input);
  }
}
<input type="file" multiple>

person guest271314    schedule 15.01.2018
comment
Это? Я думал, вы не можете назначить тип входного файла? Из соображений безопасности. - person Heinrich; 15.01.2018
comment
@Heinrich Да, можно установить FileList в свойстве <input type="file"> .files, см. Как установить объекты File и свойство длины в объекте FileList, где файлы также отражаются в объекте FormData? - person guest271314; 15.01.2018
comment
Вещи, которые вы узнаете, просто блуждая по StackOverflow, хотя я никогда не пытался это делать. - person Heinrich; 15.01.2018
comment
это es6 правильно? какая поддержка браузера для этого? - person Juliver Galleto; 15.01.2018
comment
@JuliverGalleto Код возвращает те же результаты в Chrome/Chromium и Firefox. - person guest271314; 15.01.2018
comment
@JuliverGalleto Включена версия, которая не использует class, параметры по умолчанию, элемент rest, цикл const, let или for..of в ответе. - person guest271314; 15.01.2018
comment
Остерегайтесь, это работает только в последних версиях Chrome и FF (не тестировалось в Edge, но я не думаю, что это будет работать и там). В сафари и предыдущих версиях любых браузеров это приведет к сбою, даже после транспиляции синтаксиса ES6/7: new DataTransfer был незаконным вызовом не так давно и до сих пор есть во всех браузерах, кроме хрома. Вы знаете, мне нравится ваше открытие, но я думаю, что в вашем ответе должно быть предупреждающее сообщение, поскольку, к сожалению, это все еще взлом. - person Kaiido; 15.01.2018
comment
@Kaiido Можете ли вы включить свои оценки кода в свой ответ? Не использовал, т.е. некоторое время, не пробовал ни край, ни сафари. Предлагаю использовать новейшие версии браузеров FOSS. Обновленный ответ со ссылкой на ваши комментарии и указанием того, в каких браузерах тестировался код. - person guest271314; 15.01.2018
comment
@Kaiido Определенно, я не пытаюсь сломать сеть в любом случае. - person guest271314; 15.01.2018
comment
@ guest271314 спасибо за это примечание. Что касается включения примечания в мой ответ, вы имеете в виду этот? Если это так, я уже заявляю, что только браузеры на основе Blink поддерживают конструктор DataTransfer, и что новая штука ClipboardEvent является эксплойтом ошибки FF. Это говорит о том же, что не работает в Safari и Edge. И я знаю, что вы не пытаетесь ничего сломать и, возможно, даже помогли это сделать лучше, спасибо. - person Kaiido; 15.01.2018