删除预览图像时,从文件阵列中删除特定文件



上下文

  1. 在所示的简单形式中,file输入元素允许多个文件上传
  2. 为每个文件生成一个图像预览
  3. 当单击图像时,此预览图像将被删除(为了简单起见,我没有包含删除按钮,当您单击图像时它将被删除(

附带说明的是,图像文件是通过后端的PHP提交的,后端代码都按预期工作。

当通过files输入元素附加多个文件时,它会创建一个数组,您可以通过console.log([...chooseFiles.files]);代码行看到该数组,其中显示了附加文件的详细信息。

问题

有人能解释一下,当一个图像被点击(从而在视觉上被删除/删除(时,你是如何从chooseFiles.files数组中删除特定于图像的吗?

目前,由于图像仅在视觉上被删除,因此相关图像文件仍与表单一起提交。

代码笔:https://codepen.io/thechewy/pen/xxjQwLY

let chooseFiles = document.getElementById("choose-files");
let previewWrapper = document.getElementById("preview-wrapper");
chooseFiles.addEventListener("change", (e) => {
[...chooseFiles.files].forEach(showFiles);
console.log([...chooseFiles.files]);
});
function showFiles(file) {
let previewImage = new Image();
previewImage.classList.add("img");
previewImage.src = URL.createObjectURL(file);
previewWrapper.append(previewImage); // append preview image
// -- remove the image preview visually
document.querySelectorAll(".img").forEach((i) => {
i.addEventListener("click", (e) => {
e.target.remove();
});
});
}
form {
padding: 2rem;
background: red;
width: 50%;
}
input,
button {
display: block;
margin: 1rem 0;
}
.img {
width: 200px;
height: 200px;
object-fit: cover;
margin: 0 1rem;
}
img:hover {
cursor: pointer;
}
<form enctype="multipart/form-data" method="post">
<input id="choose-files" type="file" name="choose-files[]" multiple>
<button name="submit" id="submit">SUBMIT</button>
<div id="preview-wrapper"></div>
</form>

您可以比较DOM中图像预览的内容和input中存储的FileList中的内容。然后只提交DOM中实际仍然存在的内容作为有效预览。

没有办法从FileList中删除单个项目,因为您可以在此处看到更多解释。

  • data-name属性添加到图像预览中
  • 为表单编写一个submit事件处理程序以防止默认行为
  • submit监听器中的所有.img元素中读取data-name,并将它们与FileList进行比较,同时只保留具有关联data-name的元素

let chooseFiles = document.getElementById("choose-files");
let previewWrapper = document.getElementById("preview-wrapper");
let form = document.getElementById('form');
form.addEventListener('submit', (evt) => {
evt.preventDefault()
const toSend = []
const imgs = [...document.querySelectorAll('.img')].map(img => img.dataset.name);
[...chooseFiles.files].forEach(file => {
if (imgs.includes(file.name)) {
toSend.push(file)
}
})
console.log('sending', toSend);
})
chooseFiles.addEventListener("change", (e) => {
[...e.target.files].forEach(showFiles);
});
function showFiles(file) {
let previewImage = new Image();
previewImage.dataset.name = file.name;
previewImage.classList.add("img");
previewImage.src = URL.createObjectURL(file);
previewWrapper.append(previewImage); // append preview image
// -- remove the image preview visually
document.querySelectorAll(".img").forEach((i) => {
i.addEventListener("click", (e) => {
e.target.remove();
});
});
}
form {
padding: 2rem;
background: red;
width: 50%;
}
input,
button {
display: block;
margin: 1rem 0;
}
.img {
width: 200px;
height: 200px;
object-fit: cover;
margin: 0 1rem;
}
img:hover {
cursor: pointer;
}
<form enctype="multipart/form-data" method="post" id="form">
<input id="choose-files" type="file" name="choose-files[]" multiple>
<button name="submit" id="submit">SUBMIT</button>
<div id="preview-wrapper"></div>
</form>

或者,每次删除预览图像时,可以使用DataTransfer对象从input重置FileList。这对每次要删除的单击都会做更多的工作,但有一个好处,那就是保持FileList与预览列表同步。它还在提交处理程序中使用FormData,因此您可以动态添加其他字段,并使用fetch发布数据。

let chooseFiles = document.getElementById("choose-files");
let previewWrapper = document.getElementById("preview-wrapper");
let form = document.getElementById('form');
form.addEventListener('submit', (e) => {
const fd = new FormData();

e.preventDefault();
for (const file of chooseFiles.files) {
fd.append('choose-files[]', file, file.name)
}

// You can POST this to the server with fetch like
// fetch(url, { method: 'POST', body: fd })
console.log('submit', Array.from(fd.values()));
});
chooseFiles.addEventListener("change", (e) => {
[...e.target.files].forEach(showFiles);
});
function showFiles(file) {
let previewImage = new Image();
previewImage.dataset.name = file.name;
previewImage.classList.add("img");
previewImage.src = URL.createObjectURL(file);
previewWrapper.append(previewImage); // append preview image
// -- remove the image preview visually
document.querySelectorAll(".img").forEach((i) => {
i.addEventListener("click", (e) => {
const transfer = new DataTransfer();
const name = e.target.dataset.name;

for (const file of chooseFiles.files) {
if (file.name !== name) {
transfer.items.add(file);
}
}
chooseFiles.files = transfer.files;
e.target.remove();
});
});
}
form {
padding: 2rem;
background: red;
width: 50%;
}
input,
button {
display: block;
margin: 1rem 0;
}
.img {
width: 200px;
height: 200px;
object-fit: cover;
margin: 0 1rem;
}
img:hover {
cursor: pointer;
}
<form enctype="multipart/form-data" method="post" id="form">
<input id="choose-files" type="file" name="choose-files[]" multiple>
<button name="submit" id="submit">SUBMIT</button>
<div id="preview-wrapper"></div>
</form>

最新更新