如何在FileList对象中设置File对象和length属性,其中文件也反映在FormData对象中?

gue*_*314 29 javascript form-data filelist fileapi

可以将元素的.files属性设置为例如来自不同的元素属性或属性.请参阅Make .files settable#2866,将文件上传到HTML表单并提交之间会发生什么?.<input type="file">FileList<input type="file">.filesDataTransfer.files

FileList对象有一个Symbol.iterator属性,我们可以使用它来设置一个File可迭代的对象,但是.files .length仍然设置为0并传递一个<form><input type="file">用于.files使用上述方法设置的集合,产生一个设置为的File对象..size0

如何设置Fileat FileList和set设置.lengthFileList文件数,文件在FormData()object 设置的位置?

const input = document.createElement("input");

const form = document.createElement("form");

const [...data] = [
  new File(["a"], "a.txt")
, new File(["b"], "b.txt")
];

input.type = "file";

input.name = "files";

input.multiple = true;
// set `File` objects at `FileList`
input.files[Symbol.iterator] = function*() {
   for (const file of data) {
     yield file
   };
};

form.appendChild(input);

const fd = new FormData(form);

for (const file of input.files) {
  console.log(file); // `File` objects set at `data`
}

for (const [key, prop] of fd) {
  // `"files"`, single `File` object having `lastModified` property
  // set to a time greater than last `File` object within `data`
  // at Chromium 61, only `"files"` at Firefox 57
  console.log(key, prop); 
}

console.log(input.files.length); // 0
Run Code Online (Sandbox Code Playgroud)

Kai*_*ido 44

编辑:

作为成熟的OP,在一个其要点,实际上是一个办法做到这一点?

数据传递构造函数(目前只有闪烁的支持,以及FF> = 62),应该创建一个可变的文件清单(目前铬总是返回一个新的文件清单,但它并没有真正的问题对我们来说),通过DataTransferItemList访问.

如果我没弄错的话,这是目前唯一的规范方式,但Firefox 在其ClipboardEvent构造函数的实现中有一个错误,其中相同的DataTransferItemList被设置为模式读/写,这允许一个变通方法对于FF <62.我不确定我对规格的解释,但我认为它不应该是正常的.)

因此,guest271314发现在FileList上设置任意文件的方式如下:

const dT = new ClipboardEvent('').clipboardData || // Firefox < 62 workaround exploiting https://bugzilla.mozilla.org/show_bug.cgi?id=1422655
  new DataTransfer(); // specs compliant (as of March 2018 only Chrome)
dT.items.add(new File(['foo'], 'programmatically_created.txt'));
inp.files = dT.files;
Run Code Online (Sandbox Code Playgroud)
<input type="file" id="inp">
Run Code Online (Sandbox Code Playgroud)

这个发现导致这个新的Proposal默认情况下使FileList对象可变,因为没有必要再做它.


以前(过时的)答案

你不能.脚本*不能修改FileList对象.

您只能将输入的FileList交换到另一个FileList,但不能修改它*.
(*除了清空input.value = null).

而且你不能从头开始创建FileList,也不能创建无法创建的DataTransfer对象,并且input[type=file]会创建这样的对象.

为了向您展示即使将input[type=file]FileList 设置为其他输入,也不会创建新的FileList:

var off = inp.cloneNode(); // an offscreen input

inp.onchange = e => {
  console.log('is same before', inp.files === off.files);
  off.files = inp.files; // now 'off' does have the same FileList as 'inp'
  console.log('is same after', inp.files === off.files);
  console.log('offscreen input FileList', off.files);
  console.log('resetting the offscreen input');
  off.value = null;
  console.log('offscreen input FileList', off.files);         
  console.log('inscreen input FileList', inp.files);
}
Run Code Online (Sandbox Code Playgroud)
<input type="file" id="inp">
Run Code Online (Sandbox Code Playgroud)

哦,我差点忘了FormData部分,我真的不明白说实话......

所以如果我把它弄好了,你只需要FormData.append():

var fd = new FormData();

fd.append("files[]", new Blob(['a']), 'a.txt');
fd.append("files[]", new Blob(['b']), 'b.txt');

for(let pair of fd.entries()) {
   console.log(pair[0], pair[1]); 
}
Run Code Online (Sandbox Code Playgroud)

  • 我们仍然无法在 Safari、IE/Edge 中调用 `DataTransfer` 构造函数 (2认同)