我有input
类型"file"
,我想更改其files
列表。例如:
<input type = "file" id = "fileinput" />
<script type = "text/javascript>
document.getElementById("fileinput").files = [10];
</script>
问题是未设置fileinput
元素的files
列表。我该怎么做?
答案 0 :(得分:15)
出于安全原因,浏览器会阻止javascript更改将要上传的文件:只有用户可以通过用户界面选择文件。这是为了防止邪恶的脚本上传/etc/passwd
,例如,在用户不知道的情况下。
一个例外是在表单上调用“reset”将清除文件或文件列表,但是您永远不能以编程方式添加。
答案 1 :(得分:0)
确实不可能将本地文件添加到用户没有请求的文件输入中;但是,有一种方法可以向文件输入中添加Blob
或File
对象或删除特定文件 .
等待 10 年后,解决方案终于来了。
要更改文件输入中的文件,您必须将 fileInput.files
替换为另一个 FileList
对象。
问题在于 FileList
对象是不可变的并且没有构造函数暴露给 JS。
创建自定义 FileList
的唯一方法是滥用 DataTransfer
,这是一种用于通过拖放或剪贴板传输文件的 API。
您可以通过调用不带参数的构造函数来创建 DataTransfer
:
const dataTransfer = new DataTransfer()
创建的 DataTransfer
对象有一个 files
属性,幸运的是,它是一个包含 FileList
拥有的所有文件的 DataTransfer
。
但是如何将文件添加到 DataTransfer
中?
DataTransfer
有一个与之关联的 DataTransferItemList
(可通过其 items
属性访问),该 add
具有向 DataTransfer
添加(和删除)项目的方法。< /p>
要将文件添加为项目,您必须对其调用 File
方法并传递一个 File
constructor 对象。
像这样:
dataTransfer.items.add(file)
如果您的数据不在 File
对象中(例如 Blob
或 ArrayBuffer
字节),您可以使用 this answer of mine,传递数据,文件名,以及可选的具有 type
和 lastModified
属性的对象:
const file = new File([blob], 'file.txt', {type: 'text/plain', lastModified: modificationDate})
所以,总而言之,我们有这样的事情:
new DataTransfer()
|
v
DataTransfer
| |
| +--[ .items ]---> DataTransferItemList
| |
+--[ .files ]-----+ +---[ .add(file) ]---> DataTransferItem
| ^
v |
+--[ .files ]--- FileList |
| +--- File <--- new File(data, filename, options)
| ^
v |
<input type="file"> Blob ----------+---------------------+
ArrayBuffer ---+
String --------+
我确定这现在很乱,但让我们看看一些代码!
如果您想创建一个名为 hello.txt
的包含 Hello world!
的文件并将输入设置为包含此文件,您可以这样做:
const fileInput = document.getElementById('fileInput')
const dataTransfer = new DataTransfer()
const file = new File(['Hello world!'], 'hello.txt', {type: 'text/plain'})
dataTransfer.items.add(file)
fileInput.files = dataTransfer.files
<p>Notice that the file input contains "hello.txt" now: </p>
<input type="file" id="fileInput" />
但不是替换文件,您如何编辑输入中已有的文件列表?
DataTransfer
DataTransfer
中的文件另见关于该主题的 {{3}}。
为此,我创建了一对函数,用于从 File
数组中获取和设置文件列表,因此可以在数组上执行转换,而不是使用 {{1} 执行复杂的操作}s:
DataTransfer
您可以像这样使用它们:
function getFiles(input){
const files = new Array(input.files.length)
for(let i = 0; i < input.files.length; i++)
files[i] = input.files.item(i)
return files
}
function setFiles(input, files){
const dataTransfer = new DataTransfer()
for(const file of files)
dataTransfer.items.add(file)
fileInput.files = dataTransfer.files
}
function getFiles(input){
const files = new Array(input.files.length)
for(let i = 0; i < input.files.length; i++)
files[i] = input.files.item(i)
return files
}
function setFiles(input, files){
const dataTransfer = new DataTransfer()
for(const file of files)
dataTransfer.items.add(file)
fileInput.files = dataTransfer.files
}
const fileInput = document.querySelector('#fileInput')
document.querySelector('#removeFirst').addEventListener('click', () => {
const files = getFiles(fileInput)
files.shift()
setFiles(fileInput, files)
})
document.querySelector('#removeLastModified').addEventListener('click', () => {
const files = getFiles(fileInput)
let latest = 0, latestIndex
for(let i = 0; i < files.length; i++)
if(files[i].lastModified > latest){
latest = files[i].lastModified
latestIndex = i
}
files.splice(latestIndex, 1)
setFiles(fileInput, files)
})
document.querySelector('#addFile').addEventListener('click', () => {
const files = getFiles(fileInput)
const newFiles = getFiles(document.querySelector('#addFileInput'))
files.push(...newFiles)
setFiles(fileInput, files)
})
document.querySelector('#addRandomHello').addEventListener('click', () => {
const files = getFiles(fileInput)
const newFile = new File(['Hello world!'], 'hello.txt', {type: 'text/plain'})
const index = Math.floor(Math.random() * (files.length + 1))
files.splice(index, 0, newFile)
setFiles(fileInput, files)
})
答案 2 :(得分:-1)
您想要使用multiple
元素上的input
属性。这样,在较新的浏览器中,用户将能够选择要上传的多个文件。