Comment définir les objets File et la propriété length à L'objet FileList où les fichiers sont aussi reflétés à L'objet FormData?

il est possible de définir .files propriété de <input type="file"> élément à un FileList de par exemple un <input type="file"> élément différent .files propriété ou DataTransfer.files propriété. Voir Marque .fichiers table des matières # 2866 , que se passe-t-il entre le téléchargement d'un fichier dans un formulaire HTML et sa soumission? .

FileList objet a une propriété Symbol.iterator que nous pouvons utiliser pour définir un File objet ce qui est itérable, cependant le .files .length est toujours défini à 0 et passe un <form> ayant <input type="file"> ensemble où le .files est défini en utilisant l'approche ci-dessus donne un File Objet ayant .size mis à 0 .

comment définir le File à FileList et définir .length de FileList au nombre de fichiers définis, où les fichiers sont définis à FormData() objet?

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
22
demandé sur guest271314 2017-11-05 10:59:35

1 réponses

Edit:

prouvé par l'OP , dans l'un des leur gist , il est en fait un moyen de le faire...

le constructeur DataTransfer (actuellement seulement supporté par Blink, et FF > = 62 ), devrait créer une liste de fichiers mutable (chrome actuellement toujours retourner une nouvelle liste de fichiers, mais il n'a pas vraiment d'importance pour nous) , accessible via la DataTransferItemList.

si Je ne me trompe pas, c'est actuellement la seule façon specs-wise de le faire, mais Firefox a eu un bug dans leur mise en œuvre du constructeur ClipboardEvent , où la même DataTransferItemList était et mis sur le mode lire/écrire qui a permis un travail autour de FF < 62. Je ne suis pas sûr de mon interprétation des spécifications, mais je crois qu'il ne devrait pas être accessible normalement).

Donc la manière de guest271314 trouvés pour définir des fichiers arbitraires sur une liste de Fichiers est le suivant:

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">

cette découverte a conduit à cette nouvelle proposition de rendre les objets FileList mutables par défaut, car il n'y a plus de raison de ne pas le faire.


réponse précédente (périmée)

vous ne pouvez pas. Les objets FileList ne peuvent pas être modifiés par des scripts*.

vous ne pouvez échanger la liste D'une entrée que vers une autre liste de fichiers, mais vous ne pouvez pas la modifier*.

(*Sauf pour vider avec input.value = null ).

et vous ne pouvez pas non plus créer FileList à partir de zéro, seulement DataTransfer objets qui ne peuvent pas être créés non plus, et input[type=file] va créer de tels objets.

pour vous montrer que même lors de la configuration d'une liste de fichiers input[type=file] sur celle d'une autre entrée aucune nouvelle liste de fichiers n'est créée:

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">

Oh, Et j'ai presque oublié le FormData partie, que je n'ai pas vraiment compris à dire la vérité...

donc si je l'ai eu ok, Tout ce dont vous avez besoin est tout simplement 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]); 
}
22
répondu Kaiido 2018-06-11 14:26:13