【问题标题】:Create multiple input type="file" elements with their corresponding value (FileList) according to the main input type="file" (multiple) element根据主输入 type="file" (multiple) 元素创建多个 input type="file" 元素及其对应的值 (FileList)
【发布时间】:2018-01-15 04:44:45
【问题描述】:

我有这段代码,我从多输入文件类型循环到文件

$(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)并根据循环文件给出一个值(文件)。有什么想法,建议吗?或者这甚至可能吗?

【问题讨论】:

    标签: javascript jquery fileapi


    【解决方案1】:

    是的,这个要求是可能的。您需要为每个File 对象创建一个新的FileList,然后将&lt;input type="file"&gt; 元素的.files 属性设置为填充有FileList 对象的FileList

    下面的代码在 Chromium 62+ 和 Firefox 57+ 上返回相同的结果,请参阅@Kaiido 的 cmets 在 SafariEdge 进行评估。

    // 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);
      }
    }
    &lt;input type="file" multiple&gt;

    // 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);
      }
    }
    &lt;input type="file" multiple&gt;

    【讨论】:

    • 这是吗?我以为您不能分配给输入文件类型?出于安全原因。
    • @Heinrich 是的,可以在&lt;input type="file"&gt; .files 属性上设置FileList,见How to set File objects and length property at FileList object where the files are also reflected at FormData object?
    • 你学到的东西只是在 StackOverflow 上闲逛,虽然我从未尝试过这样做。
    • @JuliverGalleto 包含了一个不使用 class、默认参数、剩余元素、constletfor..of 循环在 Answer 中的版本
    • @guest271314 感谢您的留言。关于在我的回答中包含注释,您的意思是this one?如果是这样,我已经在其中声明只有基于 Blink 的浏览器才支持 DataTransfer 构造函数,并且新的 ClipboardEvent 是对 FF 错误的利用。这与 在 Safari 和 Edge 中不起作用 相同。而且我知道你并没有试图破坏任何东西,你甚至可能帮助做到了better,所以很荣幸。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-24
    • 2011-11-12
    • 2012-11-15
    • 2015-10-10
    • 2019-01-24
    • 2021-11-26
    • 1970-01-01
    相关资源
    最近更新 更多