如何在FileList对象中设置File对象和length属性,其中文件也反映在FormData对象中? [英] How to set File objects and length property at FileList object where the files are also reflected at FormData object?
问题描述
可以将 .files
属性< input type =file>
元素设置为a FileList
例如来自不同的< input type =file>
元素 .files
property或 DataTransfer.files
property。请参阅使.files可设置#2866 ,。
It is possible to set .files
property of <input type="file">
element to a FileList
from for example a different <input type="file">
element .files
property or DataTransfer.files
property. See Make .files settable #2866, What happens between uploading a file to an HTML form and submitting it?.
FileList
对象有一个 Symbol.iterator
我们可以用来设置一个可迭代的 File
对象的属性,但 .files
.length
仍然设置为 0
并传递< form>
< input type =file>
设置使用上述方法设置 .files
的位置产生文件
对象 .size
设置为 0
。
FileList
object has a Symbol.iterator
property which we can use to set a File
object which is iterable, however the .files
.length
is still set to 0
and passing a <form>
having <input type="file">
set where the .files
is set using the above approach yields a File
object having .size
set to 0
.
如何在 FileList
设置文件
并设置 .length
FileList
到设置的文件数,其中文件设置为 FormData()
o bject?
How to set the File
at FileList
and set .length
of FileList
to the number of files set, where the files are set at 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
推荐答案
编辑:
经过OP 验证,在他们的要点,实际上有办法做到这一点......
As proven by OP, in one of their gist, there is actually a way to do it...
DataTransfer构造函数(目前仅受Blink支持,和FF> = 62 ),应该创建一个可变的FileList (chrome当前总是返回一个新的FileList,但它并不重要我们),可通过DataTransferItemList访问。
The DataTransfer constructor (currently only supported by Blink, and FF >= 62), should create a mutable FileList (chrome currently always return a new FileList, but it doesn't really matter for us), accessible through the DataTransferItemList.
如果我没弄错的话,这是目前唯一的规范方式,但Firefox的实施中有 bug ClipboardEvent构造函数,其中设置了相同的DataTransferItemList到读/写模式,它允许FF的解决方法< 62. 我不确定我对规格的解释,但我认为它不应该是正常的。)
If I'm not mistaken, this is currently the only specs-wise way to do it, but Firefox had a bug in their implementation of the ClipboardEvent constructor, where the same DataTransferItemList was and set to the mode read/write which allowed a workaround for FF < 62. I am not sure of my interpretation of the specs, but I believe it should not be accessible normally).
所以方式 guest271314 发现在FileList上设置任意文件如下:
So the way guest271314 found to set arbitrary files on a FileList is as follow:
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;
<input type="file" id="inp">
此发现导致此 new Proposal 默认情况下使FileList对象可变,因为没有必要再做它。
This discovery has lead to this new Proposal to make FileList objects mutable by default, since there is no point anymore to not do it.
你不能。脚本*不能修改FileList对象。
You can't. FileList objects cannot be modified by scripts*.
您只能将输入的FileList交换到其他FileList,但不能修改它*。
(*除了清空使用 input.value = null
)。
You can only exchange the FileList of an input to an other FileList, but you can't modify it*.
(*Except for emptying with input.value = null
).
你不能从头开始创建FileList,只能 DataTransfer 对象也无法创建,输入[type = file]
将创建此类对象。
And you can't either create FileList from scratch, only DataTransfer objects which cannot be created either, and input[type=file]
will create such objects.
为了告诉你即使将输入[type = file]
FileList设置为另一个输入,也不会创建新的FileList :
To show you that even when setting an input[type=file]
FileList to an other input's one no new FileList is created:
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);
}
<input type="file" id="inp">
哦,我差点忘了FormData部分,我真的不明白说实话......
Oh And I almost forgot the FormData part, that I don't really understood to say the truth...
所以如果我把它弄好了,你只需要 FormData.append()
:
So if I got it ok, all you need is simply 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]);
}
这篇关于如何在FileList对象中设置File对象和length属性,其中文件也反映在FormData对象中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!