无法使用 JavaScript 从输入中删除图像

Failure to delete image from input with JavaScript

提问人:claudiopb 提问时间:11/9/2023 最后编辑:Mark Rotteveelclaudiopb 更新时间:11/17/2023 访问量:36

问:

我在 HTML 和 JavaScript 下面有这段代码。有一个PHP代码可以成功地将所有内容发送到数据库,不需要显示。

<form action="" method="post" enctype="multipart/form-data">
    <label for="titulo">Título:</label>
    <input type="text" id="titulo" name="titulo" required><br><br>

    <label for="descricao">Descrição:</label><br>
    <textarea id="descricao" name="descricao" required></textarea><br><br>
    <div id="preview"></div>
    <label for="imagens">Imagens:</label>
    <input type="file" id="imagens" name="imagens[]" multiple accept="image/*">
    <small>(Você pode selecionar várias imagens segurando a tecla Ctrl)</small><br><br>

    <input type="submit" value="Cadastrar Anúncio">
</form>

<script>
    (function() {
        function previewImages() {
            var input = document.getElementById("imagens");
            var preview = document.getElementById("preview");
            preview.innerHTML = ""; // Limpa a prévia de imagens anterior

            if (input.files && input.files.length > 0) {
                for (var i = 0; i < input.files.length; i++) {
                    var reader = new FileReader();
                    reader.onload = function(e) {
                        var imageContainer = document.createElement("div");
                        imageContainer.className = "image-container";

                        var image = document.createElement("img");
                        image.src = e.target.result;
                        image.style.maxWidth = "100px"; // Define a largura máxima das miniaturas
                        imageContainer.appendChild(image);

                        var deleteButton = document.createElement("button");
                        deleteButton.innerText = "Deletar";
                        deleteButton.className = "delete-button";
                        deleteButton.addEventListener("click", function() {
                            // Função para deletar a imagem
                            imageContainer.parentNode.removeChild(imageContainer);
                            // Desanexar a imagem do input file
                            //input.value = "";
                        });
                        imageContainer.appendChild(deleteButton);

                        preview.appendChild(imageContainer);
                    };
                    reader.readAsDataURL(input.files[i]);
                }
            }
        }

        // Adicione o evento onchange ao campo de entrada de arquivo fora das tags HTML
        var imagensInput = document.getElementById("imagens");
        imagensInput.onchange = previewImages;
    })();
</script>

问题在于,当我单击图像缩略图下方出现的“删除”按钮时,它实际上删除了缩略图,并且似乎删除了临时文件。

这是已经显示的代码的隔离部分,负责删除图像缩略图。

var deleteButton = document.createElement("button");
deleteButton.innerText = "Deletar";
deleteButton.className = "delete-button";
deleteButton.addEventListener("click", function() {
    // Função para deletar a imagem
    imageContainer.parentNode.removeChild(imageContainer);
    // Desanexar a imagem do input file
    //input.value = "";
});
imageContainer.appendChild(deleteButton);

preview.appendChild(imageContainer);

但是,附加到输入的所有图像(为多个文件创建)都将发送到数据库,包括被按钮删除的图像。

正确的做法是保留被按钮删除的图像,并防止将其发送到数据库。

我已经在其他线程中阅读了给出此解决方案的答案:

reader.onload = function(e) {
//rest of code omitted
      input.value = "";
});

但这不起作用,因为当您插入这行代码时,所有图像都会被删除,而不是唯一选择的图像。

我该如何解决?

JavaScript HTML 表单 DOM

评论

0赞 CBroe 11/9/2023
您的删除按钮不会对文件输入字段中包含的实际文件选择执行任何操作,它所做的只是删除您为预览目的添加的元素。需要如何处理这样的事情 - 请参阅副本。img
0赞 chrwahl 11/27/2023
我可以看到问题所在。文件列表 () 是只读的。我现在没有时间,但我的想法是维护所选文件的数组(以及您已经拥有的 UI 部分)。可以从该列表中添加文件(用于添加一个或多个文件的文件选择器)或删除文件(删除按钮)。最后(在提交事件上),您可以创建一个 formData 对象,并将所有表单字段的值和数组中的文件相加。让 JavaScript 使用 fetch 请求处理 submit 事件,并将 formData 对象作为正文。input.files

答:

0赞 chrwahl 12/2/2023 #1

这是一个很长的例子,但我的想法是维护所选文件的数组(这里是 Map 对象)。可以从该数组中添加文件(用于添加一个或多个文件的文件选择器)或删除文件(删除按钮)。最后(在提交事件上),您可以创建一个 formData 对象,并将所有表单字段的值和数组中的文件相加。让 JavaScript 使用 fetch 请求处理 submit 事件,并将 formData 对象作为正文。

var images = new Map();
const preview = document.getElementById('preview');

document.forms.form01.addEventListener('submit', e => {
  e.preventDefault();
  let data = new FormData(e.target);
  data.delete('images');
  images.forEach((file, id) => {
    let blob = dataURItoBlob(file.src);
    data.append('images[]', blob, file.name);
  });
  fetch('post.php', {
    method: 'POST',
    body: data
  });
});

document.forms.form01.images.addEventListener('input', e => {
  let input = e.target;
  [...input.files].forEach(file => {
    let reader = new FileReader();
    reader.fileinfo = {
      name: file.name,
      lastModified: file.lastModified,
      size: file.size,
      type: file.type
    };
    reader.addEventListener('load', e => {
      let file = e.target.fileinfo;
      file.src = e.target.result;
      images.set(`id${file.lastModified}${file.size}`, file);
      previewImages();
    });
    reader.readAsDataURL(file);
  });
  input.value = "";
});

document.forms.form01.addEventListener('click', e => {
  switch (e.target.name) {
    case 'delete':
      images.delete(e.target.value);
      previewImages();
      break;
    case 'browse':
      e.target.form.images.click();
      break;
  }
});

function previewImages() {
  // add images to the preview div if not already there
  images.forEach((file, id) => {
    if (!preview.querySelector(`#${id}`)) {
      let imageContainer = document.createElement("div");
      imageContainer.className = "image-container";
      imageContainer.id = id;

      let image = document.createElement("img");
      image.src = file.src;
      image.style.maxWidth = "100px"; // Define a largura máxima das miniaturas
      imageContainer.appendChild(image);

      var deleteButton = document.createElement("button");
      deleteButton.innerText = "Deletar";
      deleteButton.name = "delete";
      deleteButton.type = "button";
      deleteButton.value = id;
      imageContainer.appendChild(deleteButton);
      preview.appendChild(imageContainer);
    }
  });
  // remove images from preview if not in the Map object
  preview.querySelectorAll('.image-container').forEach(div => {
    if (!images.has(div.id)) {
      div.remove();
    }
  });
}

function dataURItoBlob(dataURI) {
  let byteString = atob(dataURI.split(',')[1]);
  let mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
  let ab = new ArrayBuffer(byteString.length);
  let ia = new Uint8Array(ab);
  for (var i = 0; i < byteString.length; i++) {
    ia[i] = byteString.charCodeAt(i);
  }
  return new Blob([ab], {
    type: mimeString
  });
}
<form name="form01" action="" method="post" enctype="multipart/form-data">
  <label for="titulo">Título:</label>
  <input type="text" id="titulo" name="titulo" required><br><br>

  <label for="descricao">Descrição:</label><br>
  <textarea id="descricao" name="descricao" required></textarea><br><br>
  <div id="preview"></div>
  <label>Imagens: <button type="button" name="browse">Browse…</button>
    <input type="file" name="images" multiple accept="image/*" style="display:none">
  </label>
  <small>(Você pode selecionar várias imagens segurando a tecla Ctrl)</small><br><br>

  <input type="submit" value="Cadastrar Anúncio">
</form>