我有一個檔案上傳器,當從影像預覽中洗掉影像時,該影像將從FileList. 這是通過創建一個新陣列并從新陣列中洗掉目標(已洗掉)元素,然后使用dataTranser()將其設定為“檔案”輸入元素的 FileList 來完成的。一切正常。
問題
我遇到的問題是,如果在提交之前通過檔案選擇器輸入元素添加了更多檔案(無論是否洗掉了任何檔案),即使影像預覽在顯示的數量和特定影像方面是正確的,檔案是上傳/提交的始終是使用最新選擇添加的檔案。如果只選擇一組檔案,這當然沒問題,但如果在提交之前添加了其他影像/檔案,則第二組會覆寫第一組(盡管影像仍然在影像預覽中正確顯示)。
如果您通過代碼示例中的“瀏覽”按鈕選擇要上傳的檔案,然后再次單擊“瀏覽”按鈕以添加更多影像,則要查看問題,您會明白我的意思。
問題
我如何得到它,以便在添加第二個檔案選擇時將它們添加到現有陣列中并且不覆寫它?
注意 1:為了使代碼更簡單,我設定了它,以便在單擊特定影像預覽時洗掉影像,而不是通過“洗掉影像”按鈕。
注意 2:用于處理表單的后端代碼是 PHP,但我沒有包含它,因為它不是問題的一部分。
代碼筆: https ://codepen.io/thechewy/pen/wvjOdEq
let attachFiles = document.getElementById("attach-files");
let previewWrapper = document.getElementById("show-selected-images");
let form = document.getElementById("upload-images-form");
attachFiles.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 and change FileList
document.querySelectorAll(".img").forEach((i) => {
i.addEventListener("click", (e) => {
const transfer = new DataTransfer();
const name = e.target.dataset.name;
for (const file of attachFiles.files) {
if (file.name !== name) {
transfer.items.add(file);
}
}
attachFiles.files = transfer.files;
//remove image preview element when image is clicked
e.target.remove();
});
});
}
form {
padding: 1rem 2rem;
width: 50%;
border: 1px solid;
}
input,
button {
display: block;
margin: 2rem 0;
}
.img {
width: 200px;
height: 200px;
object-fit: cover;
margin: 0 1rem;
}
img:hover {
cursor: pointer;
}
<form enctype="multipart/form-data" method="post" id="upload-images-form">
<input id="attach-files" type="file" name="attach-files[]" multiple>
<button name="submit" id="submit">SUBMIT</button>
<div id="show-selected-images"></div>
</form>
uj5u.com熱心網友回復:
這使用一個DataTransfer物件呼叫submitData到事件add期間選擇的檔案change來attachFiles,并將remove它們在click事件上進行<img>預覽。
如果你想對FileListon做一些不同的事情,請告訴我submit,比如可能用 POST 它fetch。
let attachFiles = document.getElementById("attach-files");
let previewWrapper = document.getElementById("show-selected-images");
let form = document.getElementById("upload-images-form");
let submitData = new DataTransfer();
attachFiles.addEventListener("change", (e) => {
const currentSubmitData = Array.from(submitData.files);
previewWrapper.replaceChildren();
[...e.target.files].forEach(file => {
if (currentSubmitData.every(currFile => currFile.name !== file.name)) {
submitData.items.add(file);
}
});
[...submitData.files].forEach(showFiles);
attachFiles.files = submitData.files;
});
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 and change FileList
document.querySelectorAll(".img").forEach((i) => {
i.addEventListener("click", (e) => {
const name = e.target.dataset.name;
[...submitData.files].forEach((file, idx) => {
if (file.name === name) {
submitData.items.remove(idx);
}
});
attachFiles.files = submitData.files;
//remove image preview element when image is clicked
e.target.remove();
});
});
}
form {
padding: 1rem 2rem;
width: 50%;
border: 1px solid;
}
input,
button {
display: block;
margin: 2rem 0;
}
.img {
width: 200px;
height: 200px;
object-fit: cover;
margin: 0 1rem;
}
img:hover {
cursor: pointer;
}
<form enctype="multipart/form-data" method="post" id="upload-images-form">
<input id="attach-files" type="file" name="attach-files[]" multiple>
<button name="submit" id="submit">SUBMIT</button>
<div id="show-selected-images"></div>
</form>
這是一種替代方法,可以清理代碼的其他一些區域。有解釋該方法的行內注釋。
大多數情況下,它利用addEventListener您動態創建Image()的click在附加到 DOM 之前附加偵聽器,而不是附加然后查詢 DOM 以隨后附加偵聽器。還使用currentTarget而不是target確保事件的任何冒泡階段不會觸發意外 DOM 節點的偵聽器。
let attachFiles = document.getElementById("attach-files");
let previewWrapper = document.getElementById("show-selected-images");
let form = document.getElementById("upload-images-form");
let submitData = new DataTransfer();
attachFiles.addEventListener("change", (e) => {
const currentSubmitData = Array.from(submitData.files);
// For each addded file, add it to submitData if not already present
[...e.target.files].forEach(file => {
if (currentSubmitData.every(currFile => currFile.name !== file.name)) {
submitData.items.add(file);
}
});
// Sync attachFiles FileList with submitData FileList
attachFiles.files = submitData.files;
// Clear the previewWrapper before generating new previews
previewWrapper.replaceChildren();
// Generate a preview <img> for each selected file
[...submitData.files].forEach(showFiles);
});
function showFiles(file) {
let previewImage = new Image();
// Set relevant <img> attributes
previewImage.dataset.name = file.name;
previewImage.classList.add("img");
previewImage.src = URL.createObjectURL(file);
// Add click event listener to <img> preview
previewImage.addEventListener('click', e => {
const target = e.currentTarget;
const name = target.dataset.name;
// Remove the clicked file from the submitData
[...submitData.files].forEach((file, idx) => {
if (file.name === name) {
submitData.items.remove(idx);
}
});
// Reset the attachFiles FileList
attachFiles.files = submitData.files;
// Remove the <img> node from the DOM
target.remove();
});
// Append <img> preview node to DOM
previewWrapper.append(previewImage);
}
form {
padding: 1rem 2rem;
width: 50%;
border: 1px solid;
}
input,
button {
display: block;
margin: 2rem 0;
}
.img {
width: 200px;
height: 200px;
object-fit: cover;
margin: 0 1rem;
}
img:hover {
cursor: pointer;
}
<form enctype="multipart/form-data" method="post" id="upload-images-form">
<input id="attach-files" type="file" name="attach-files[]" multiple>
<button name="submit" id="submit">SUBMIT</button>
<div id="show-selected-images"></div>
</form>
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/518616.html
