javascript - 如何分别从用户那里获取多个文件?
问题描述
目前,我正在开发拖放功能。问题是我无法弄清楚如何分别从用户那里获取多个文件。假设我们有一个拖放区容器,当用户将图像拖放到该容器时,它会将它们分配给<input type="file">
. 比方说,用户在这里放了一张图片,然后决定放另一张图片,我们必须以某种方式将第二张图片添加到输入中。我尝试在互联网上寻找解决方案(当然:))但没有找到解决这个问题的方法。
这是我的 HTML:
<form action="" method="POST" enctype="multipart/form-data">
<div class="drop_zone">
<span class="drop_zone__prompt">Drop your files here</span>
<input required name="images" type="file" multiple class="drop_zone__input">
</div>
<input type="submit" value="Отправить">
</form>
JavaScript:
document.querySelectorAll('.drop_zone__input').forEach(InputElement => {
const dropZoneElement = InputElement.closest('.drop_zone');
dropZoneElement.addEventListener('drop', e => {
e.preventDefault();
if (e.dataTransfer.files.length){
InputElement.files = e.dataTransfer.files;
}
});
我试过这个:
dropZoneElement.addEventListener('drop', e => {
e.preventDefault();
if (e.dataTransfer.files.length){
myfiles = e.dataTransfer.add(InputElement.files);
InputElement.files = myfiles;
}
});
但它返回错误说'e.dataTransfer.add 不是函数'
为什么我尝试这个:
我在这里找到了 add() 方法
这篇文章说:
DataTransferItemList 对象是代表被拖动项目的 DataTransferItem 对象的列表。在拖动操作期间,每个 DragEvent 都有一个 dataTransfer 属性,该属性是一个 DataTransferItemList。
解决方案
实际上,有一种方法可以做到这一点。这远非简单,但它确实有效。
创建对象的唯一方法FileList
是创建自定义DataTransfer
对象。您可以使用 向其中添加文件,并通过dataTransfer.items.add()
获取对应的文件。FileList
dataTransfer.files
DataTransfer
因此,每次要添加文件时都创建一个新对象,将现有文件和新文件添加到其中,并将其分配给输入元素FileList
的files
属性。
注意:您不能
DataTransfer
为此使用 drop 事件的对象,因为它是只读的。
document.querySelectorAll('.drop_zone__input').forEach(InputElement => {
const dropZoneElement = InputElement.closest('.drop_zone');
dropZoneElement.addEventListener('dragover', e => {
e.preventDefault()
});
dropZoneElement.addEventListener('drop', e => {
e.preventDefault();
//Create a new DataTransfer object
const dataTransfer = new DataTransfer
//Add new files from the event's DataTransfer
for(let i = 0; i < e.dataTransfer.files.length; i++)
dataTransfer.items.add(e.dataTransfer.files[i])
//Add existing files from the input element
for(let i = 0; i < InputElement.files.length; i++)
dataTransfer.items.add(InputElement.files[i])
//Assign the files to the input element
InputElement.files = dataTransfer.files
});
})
.drop_zone{
height: 200px;
width: 200px;
border: solid black 1px;
}
<form action="" method="POST" enctype="multipart/form-data">
<div class="drop_zone">
<span class="drop_zone__prompt">Drop your files here</span>
<input required name="images" type="file" multiple class="drop_zone__input">
</div>
<input type="submit" value="Отправить">
</form>
您还可以重复使用相同的DataTransfer
对象,因此您不必重新添加现有文件。
但是,在这种情况下,您还必须处理input
输入元素上的事件。
document.querySelectorAll('.drop_zone__input').forEach(InputElement => {
const dropZoneElement = InputElement.closest('.drop_zone');
const dataTransfer = new DataTransfer
dropZoneElement.addEventListener('dragover', e => {
e.preventDefault()
});
dropZoneElement.addEventListener('drop', e => {
e.preventDefault();
//Add new files from the event's DataTransfer
for(let i = 0; i < e.dataTransfer.files.length; i++)
dataTransfer.items.add(e.dataTransfer.files[i])
//Assign the files to the input element
InputElement.files = dataTransfer.files
});
InputElement.addEventListener('input', e => {
dataTransfer.items.clear()
for(let i = 0; i < InputElement.files.length; i++)
dataTransfer.items.add(InputElement.files[i])
})
})
.drop_zone{
height: 200px;
width: 200px;
border: solid black 1px;
}
<form action="" method="POST" enctype="multipart/form-data">
<div class="drop_zone">
<span class="drop_zone__prompt">Drop your files here</span>
<input required name="images" type="file" multiple class="drop_zone__input">
</div>
<input type="submit" value="Отправить">
</form>
或者,如果您想在与文件输入交互时添加文件而不是替换它们,您可以这样做:
document.querySelectorAll('.drop_zone__input').forEach(InputElement => {
const dropZoneElement = InputElement.closest('.drop_zone');
const dataTransfer = new DataTransfer
dropZoneElement.addEventListener('dragover', e => {
e.preventDefault()
});
dropZoneElement.addEventListener('drop', e => {
e.preventDefault();
//Add new files from the event's DataTransfer
for(let i = 0; i < e.dataTransfer.files.length; i++)
dataTransfer.items.add(e.dataTransfer.files[i])
//Assign the files to the input element
InputElement.files = dataTransfer.files
});
InputElement.addEventListener('input', e => {
e.preventDefault()
for(let i = 0; i < InputElement.files.length; i++)
dataTransfer.items.add(InputElement.files[i])
InputElement.files = dataTransfer.files
})
})
.drop_zone{
height: 200px;
width: 200px;
border: solid black 1px;
}
<form action="" method="POST" enctype="multipart/form-data">
<div class="drop_zone">
<span class="drop_zone__prompt">Drop your files here</span>
<input required name="images" type="file" multiple class="drop_zone__input">
</div>
<input type="submit" value="Отправить">
</form>
DataTransfer
您可以使用以下方法从对象中删除文件dataTransfer.items.remove()
:
document.querySelectorAll('.drop_zone__input').forEach(InputElement => {
const dropZoneElement = InputElement.closest('.drop_zone');
const removeFirstElement = dropZoneElement.querySelector('.drop_zone__remove_first')
const dataTransfer = new DataTransfer
dropZoneElement.addEventListener('dragover', e => {
e.preventDefault()
});
dropZoneElement.addEventListener('drop', e => {
e.preventDefault();
//Add new files from the event's DataTransfer
for(let i = 0; i < e.dataTransfer.files.length; i++)
dataTransfer.items.add(e.dataTransfer.files[i])
//Assign the files to the input element
InputElement.files = dataTransfer.files
});
InputElement.addEventListener('input', e => {
e.preventDefault()
for(let i = 0; i < InputElement.files.length; i++)
dataTransfer.items.add(InputElement.files[i])
InputElement.files = dataTransfer.files
})
removeFirstElement.addEventListener('click', () => {
dataTransfer.items.remove(0)
InputElement.files = dataTransfer.files
})
})
.drop_zone{
height: 200px;
width: 200px;
border: solid black 1px;
}
<form action="" method="POST" enctype="multipart/form-data">
<div class="drop_zone">
<span class="drop_zone__prompt">Drop your files here</span>
<input required name="images" type="file" multiple class="drop_zone__input">
<input type="button" class="drop_zone__remove_first" value="Remove first file">
</div>
<input type="submit" value="Отправить">
</form>
推荐阅读
- c - 使用分而治之的数组的第二大元素
- java - 当舞台被隐藏在 JavaFX 中时,我怎样才能得到?
- julia - 打印帮助?来自 Julia 函数的信息
- go - Go Module : main.go 文件在 go build 后被覆盖
- java - 如何修复“无法为数据库提供空上下文” - Android Room
- tensorflow - 如何像 Pytorch 中的 conv2d 参数“groups”一样在 tensorflow 中获得每个通道的卷积?
- angular - 在对话框中打开时,角度垫滑块从 100 动画到 0
- reactjs - 将右侧网格大小与左侧动态网格的总高度对齐
- android - 任务 ':app:checkDebugDuplicateClasses' 执行失败。离子4安卓
- c# - 无法从 task.IsFaulted 条件下调用方法完成