Как установить объекты File и длину в объекте FileList, где файлы также отражаются в объекте FormData?
Можно установить .files
собственностью <input type="file">
элемент к FileList
например, из другого <input type="file">
элемент .files
собственность или DataTransfer.files
имущество. См. Make.files settable # 2866, Что происходит между загрузкой файла в HTML-форму и его отправкой?,
FileList
объект имеет Symbol.iterator
свойство, которое мы можем использовать, чтобы установить File
объект, который является итеративным, однако .files
.length
по-прежнему настроен на 0
и прохождение <form>
имеющий <input type="file">
установить где .files
устанавливается с использованием вышеуказанного подхода дает File
объект, имеющий .size
установлен в 0
,
Как установить File
в FileList
и установить .length
из FileList
на количество файлов, где файлы установлены в FormData()
объект?
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
1 ответ
Редактировать:
Как доказано OP, в одном из их существований есть способ сделать это...
Конструктор DataTransfer (в настоящее время поддерживается только Blink и FF> = 62) должен создать изменяемый FileList (в настоящее время chrome всегда возвращает новый FileList, но для нас это не имеет значения), доступный через 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;
<input type="file" id="inp">
Это открытие привело к этому новому предложению сделать объекты 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);
}
<input type="file" id="inp">
О, и я почти забыл часть 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]);
}