2017-11-05 2 views
17

Es ist möglich, .files Eigenschaft <input type="file"> Element zu einem FileList von zum Beispiel eine andere <input type="file"> Element .files Eigenschaft oder DataTransfer.files Eigenschaft festlegen. Siehe Make .files settable #2866, What happens between uploading a file to an HTML form and submitting it?.Wie legen Sie die Dateiobjekte und die Längeneigenschaft im FileList-Objekt fest, wo die Dateien auch im FormData-Objekt wiedergegeben werden?

FileList Objekt hat eine Symbol.iterator Eigenschaft, die wir jedoch ein File Objekt zu setzen, die iterable ist verwenden können, wird die .files.length noch auf 0 und vorbei ein <form> mit <input type="file"> Satz, wo die .files gesetzt wird, um den oben genannten Ansatz ergibt eine File Objekt mit .size festgelegt auf 0.

Wie die File bei FileList setzen und setzen .length von FileList auf die Anzahl der Dateien festgelegt, in dem die Dateien auf FormData() Objekt festgelegt werden?

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

+0

wurde in FF57 fixiert sehen https://developer.mozilla.org/en-US/Firefox/Releases/57#DOM –

Antwort

11

Edit:

Als bewiesen durch OP, in einem der their gist gibt tatsächlich einen Weg, es ...

Die DataTransfer constructor zu tun ist (derzeit nur von Blink unterstützt), sollte eine veränderbare FileList erstellen (chrome gibt immer eine neue FileList zurück, aber es ist nicht wirklich m atter für uns), zugänglich durch die DataTransferItemList.

Wenn ich mich nicht irre, ist dies derzeit der einzige technische Weg, aber Firefox scheint auch einen Fehler in der Implementierung der ClipboardEvent constructor, wo die gleiche DataTransferItemList zugänglich ist und auf den Modus eingestellt zu haben lesen/schreiben. Ich bin mir meiner Interpretation der Spezifikationen nicht sicher, aber ich glaube, dass es normalerweise nicht zugänglich sein sollte).

So ist die Art und Weise guest271314 gefunden beliebige Dateien auf einem Dateiliste zu setzen, ist wie folgt:

const dT = new ClipboardEvent('').clipboardData || // Firefox bug? 
 
    new DataTransfer();        // specs compliant 
 
dT.items.add(new File(['foo'], 'programmatically_created.txt')); 
 
inp.files = dT.files;
<input type="file" id="inp">

Diese Entdeckung dieser new Proposal führen hat Filelist machen Objekte änderbare standardmäßig , da es keinen Sinn mehr macht, es nicht zu tun.


Zurück (veraltet) Antwort

können Sie nicht. FileList-Objekte können nicht durch Skripte * geändert werden.

Sie können die FileList einer Eingabe nur mit einer anderen FileList austauschen, aber Sie können sie nicht ändern *.
(* Außer zum Entleeren mit input.value = null).

Und Sie können FileList nicht von Grund auf neu erstellen, nur DataTransfer Objekte, die auch nicht erstellt werden können, und input[type=file] wird solche Objekte erstellen.

Um Ihnen zu zeigen, dass selbst wenn eine input[type=file] Dateiliste an eine andere Eingabe des einen keine neue Dateiliste erstellt setzt:

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, und ich vergaß fast die Formdata Teil, dass ich don ‚t wirklich die Wahrheit zu sagen verstanden ...

Also, wenn ich es in Ordnung, bekam alles, was Sie brauchen, ist einfach 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]); 
 
}

+0

Wäre es nicht besser, die vorherige einfach herausschneiden Antwort (auf die noch immer durch den Bearbeitungsverlauf verwiesen werden kann), damit die Antwort präziser sein kann? –

+0

@SamuelLiew der neue Teil ist immer noch * hauptsächlich ein Hack *. Die neuen Spezifikationen (ab heute nur in Blink implementiert) erlauben dies, aber es ist nicht wirklich von Design, es ist eher ein Zufall. Der FF-Fallback ist ein Missbrauch eines kleineren Fehlers in ihrer Implementierung. Obwohl es ein interessanter Hack ist, der wahrscheinlich zu einer echten API führen wird (https://github.com/whatwg/html/issues/3269), glaube ich, dass der zweite Teil dieser Antwort vorläufig ist Darüber hinaus ist es auch bei einem FileList-Konstruktor immer noch gültig: Sie können eine FileList nicht ändern, sondern nur neue erstellen. – Kaiido

Verwandte Themen