如何更改文件输入的文件列表

dav*_*ave 8 html javascript set

我有这种input类型"file",我想改变它的files列表.例:

<input type = "file" id = "fileinput" />
<script type = "text/javascript>
  document.getElementById("fileinput").files = [10];
</script>
Run Code Online (Sandbox Code Playgroud)

问题是没有设置fileinput元素的files列表.我该怎么做?

FZs*_*FZs 54

确实不可能将本地文件添加用户未请求的文件输入中;但是,一种方法可以添加BlobFile对象到文件输入或从文件输入中删除特定文件。


要更改文件输入中的文件,您必须将 替换fileInput.files为另一个FileList对象。

问题是FileList对象是不可变的,并且没有暴露给 JS 的构造函数。

创建自定义的唯一方法FileList是滥用DataTransfer,这是一种设计用于使用拖放或通过剪贴板传输文件的 API。

所有主流浏览器都支持它,但 IE 不支持,并且仅从 Safari 14.1 版本开始支持。您可以在这里查看。

您可以DataTransfer通过调用不带参数的构造函数来创建对象:

const dataTransfer = new DataTransfer()
Run Code Online (Sandbox Code Playgroud)

创建的DataTransfer对象有一个files属性,幸运的是,该属性FileList包含该对象拥有的所有文件DataTransfer

但那么如何将文件添加到呢DataTransfer

每个DataTransfer都有一个DataTransferItemList与之关联的(可通过其items属性访问),该属性具有向DataTransfer.

要添加文件,您必须调用add它的方法并传递一个File对象。

就像这样:

dataTransfer.items.add(file)
Run Code Online (Sandbox Code Playgroud)

如果您的数据不在File对象中(例如,一个BlobArrayBuffer多个字节),则可以使用File构造函数,传递数据、文件名以及可选的具有typelastModified属性的对象:

const file = new File([blob], 'file.txt', {type: 'text/plain', lastModified: modificationDate})
Run Code Online (Sandbox Code Playgroud)

所以,总而言之,我们有这样的东西:

new DataTransfer()
 |
 v
DataTransfer 
 |  |
 |  +--[ .items ]---> DataTransferItemList
 |                      |
 +--[ .files ]------+   +---[ .add(file) ]---> DataTransferItem
                    |               ^
                    v               |
 +--[ .files ] <-- FileList         |
 |                                  +--- File <--- new File([data], filename, options)
 |                                                            ^
 |                                                            |
<input type="file">      Blob ----------+---------------------+
                         ArrayBuffer ---+
                         string --------+
Run Code Online (Sandbox Code Playgroud)

我确信现在这很混乱,但让我们看一些代码!

如果您想创建一个名为hello.txtcontains的文件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
Run Code Online (Sandbox Code Playgroud)
<p>Notice that the file input contains "hello.txt" now: </p>
<input type="file" id="fileInput" />
Run Code Online (Sandbox Code Playgroud)

但是,您如何编辑输入中已有的文件列表,而不是替换文件?

  1. 创建一个DataTransfer
  2. 添加输入中除要删除的文件之外的所有现有文件
  3. 添加您要添加​​的文件
  4. 将输入中的文件替换为DataTransfer

另请参阅我关于该主题的回答

为此,我创建了一对函数,用于从Files 数组中获取和设置文件列表,因此可以在数组上执行转换,而不是使用DataTransfers 执行复杂的操作:

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)
  input.files = dataTransfer.files
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它们:

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)
  input.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)
})
Run Code Online (Sandbox Code Playgroud)
Hint: hover over the file input to see the list of all files in it <br>
<input type="file" id="fileInput" multiple ><br><br>
<button id="removeFirst">Remove first file</button><br>
<button id="removeLastModified">Remove latest modified file</button><br>
<button id="addFile">Append file from this input</button> <input type="file" id="addFileInput" /><br>
<button id="addRandomHello">Add a hello.txt file to a random place</button><br>
Run Code Online (Sandbox Code Playgroud)


odr*_*drm 15

出于安全原因,浏览器会阻止javascript更改将要上传的文件:只有用户才能通过用户界面选择文件.这是为了防止恶意脚本上传/etc/passwd,例如,在用户不知道的情况下.

一个例外是在表单上调用"reset"将清除文件或文件列表,但您永远不能以编程方式添加.

  • 那么当多次单击它时,如何将更多文件添加到文件输入的文件列表中? (4认同)