javascript 如何以编程方式更改文件输入的FileList?

f45qwnt8  于 2023-05-05  发布在  Java
关注(0)|答案(4)|浏览(253)

我有一个"file"类型的input,我想更改它的files列表。示例:

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

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

xu3bshqb

xu3bshqb1#

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

要更改文件输入中的文件,必须将fileInput.files替换为另一个FileList对象。
问题是FileList对象是不可变的没有暴露给JS的构造函数
创建自定义FileList的唯一方法是滥用DataTransfer,这是一种专为使用拖放或通过剪贴板传输文件而设计的API。
所有主流浏览器都支持它,但IE不支持,Safari从14.1版开始支持。你可以检查here
您可以通过调用不带参数的构造函数来创建DataTransfer对象:

const dataTransfer = new DataTransfer()

创建的DataTransfer对象有一个files属性,幸运的是,它是一个FileList,包含DataTransfer拥有的所有文件。
但是如何将文件添加到DataTransfer
每个DataTransfer都有一个与之关联的DataTransferItemList(可通过其items属性访问),该DataTransferItemList具有向DataTransfer添加(或从DataTransfer删除)项的方法。
要添加一个文件,必须调用add方法并传递一个File对象。
就像这样:

dataTransfer.items.add(file)

如果您有不在File对象中的数据(例如BlobArrayBuffer字节),您可以使用File constructor,将数据,文件名以及具有typelastModified属性的对象传递给它:

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)
 |                                                            ^
 |                                                            |
<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" />

但是,除了替换文件之外,如何编辑输入中已有的文件列表呢?
1.创建DataTransfer
1.从输入中添加除要删除的文件之外的所有现有文件
1.添加要添加的文件
1.将输入中的文件替换为DataTransfer中的文件
this answer of mine关于这个主题。
为此,我创建了一对函数,用于从File s数组中获取和设置文件列表,因此可以在数组上执行转换,而不是使用DataTransfer s执行复杂的操作:

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
}

你可以这样使用它们:

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)
})
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>
9rnv2umw

9rnv2umw2#

出于安全原因,浏览器会阻止JavaScript更改将要上传的文件:只有用户可以通过用户界面选择文件。这是为了防止恶意脚本在用户不知情的情况下上传/etc/passwd
唯一的例外是,在表单上调用“reset”将清除文件或文件列表,但您永远不能以编程方式添加到。

dly7yett

dly7yett3#

const fileInput = document.getElementById('fileInput ')
const dataTransfer = new DataTransfer()
const file = new File(['Hello world!'],' hello.txt ',{type:'text/plain'})
dataTransfer.items.add(文件)
fileInput.files = dataTransfer.files
这应该能保存你一命

ecfsfe2w

ecfsfe2w4#

您需要的是在input元素上使用multiple属性。这样,在较新的浏览器用户将能够选择多个文件上传。

相关问题