You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JS多文件上传删除异常:循环重复执行与文件批量丢失问题排查修复

多文件上传删除功能问题排查与修复

问题现象

  • 单个文件输入框上传多张图片后,删除第一个位置的图片会导致该输入框内所有文件丢失
  • 删除操作仅影响当前输入框,不会波及其他输入框
  • 点击第一个.remove元素时,console.log(key)会执行多次(次数等于上传图片数量)

问题根源

  1. 重复绑定点击事件:每次上传图片时,都会对所有.remove元素重新绑定点击事件。比如上传5张图,每个删除按钮会被绑定5次点击事件,导致点击一次触发多次执行。
  2. 索引变量混淆:删除事件中使用的key是.each()循环的索引,这个索引和文件在dataTransfer中的实际索引不匹配,重复绑定后每次绑定的key值是循环时的索引,导致删除时错误移除多个文件。
  3. 事件绑定时机错误:在fileReader.onloadend中绑定事件,每次加载完一张图片就重新绑定所有删除按钮的事件,造成重复绑定。

修复代码

HTML(无需修改)

<script src="https://code.jquery.com/jquery-3.6.4.js" integrity="sha256-a9jBBRygX1Bh5lt8GZjXDzyOB+bWve9EiO7tROUtj/E=" crossorigin="anonymous"></script>

<form action="" method="post" enctype="multipart/form-data">
  <div class="field" align="left">
    <div class="upload__files-wrap"></div>
    <input type="file" class="files" accept="image/*" name="hinhanh1[]" multiple />
  </div>

  <div class="field" align="left">
    <div class="upload__files-wrap"></div>
    <input type="file" class="files" accept="image/*" name="hinhanh2[]" multiple />
  </div>
  <br>
  <input type="submit" value="submit" name="submit">
</form>

CSS(无需修改)

input[type="file"] {
  display: block;
}

.upload__files-wrap {
  display: flex;
  flex-wrap: wrap;
  margin: 0 -10px;
}

.imageThumb {
  height: 200px;
  width: 250px;
}

.pip {
  display: inline-block;
  margin: 10px 10px 0 0;
  position: relative;
}

.remove {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background-color: rgba(0, 0, 0, 0.5);
  position: absolute;
  top: 10px;
  right: 10px;
  text-align: center;
  line-height: 24px;
  z-index: 1;
  cursor: pointer;
}

.remove:after {
  content: "\2716";
  font-size: 14px;
  color: white;
}

JavaScript(修复后)

$(function () {
  if (window.File && window.FileList && window.FileReader) {
    $(".files").each(function (inputKey) {
      var files_name_arr = [];
      var dataTransfer = new DataTransfer();
      const $wrap = $(this).prev(".upload__files-wrap");

      // 事件委托绑定删除事件,避免重复绑定
      $wrap.on("click", ".remove", function() {
        const $pip = $(this).closest(".pip");
        const fileName = $pip.find(".imageThumb").attr("title");
        const fileIndex = files_name_arr.indexOf(fileName);
        
        if (fileIndex !== -1) {
          dataTransfer.items.remove(fileIndex);
          files_name_arr.splice(fileIndex, 1);
          $pip.remove();
          $(".files")[inputKey].files = dataTransfer.files;
        }
      });

      $(this).change(function (e) {
        // 添加新文件到dataTransfer,避免重复
        for (let file of e.target.files) {
          if (!files_name_arr.includes(file.name)) {
            dataTransfer.items.add(file);
            files_name_arr.push(file.name);
            
            // 读取并渲染图片
            let fileReader = new FileReader();
            fileReader.onloadend = function (loadEvent) {
              $wrap.append(
                '<div class="pip">' +
                  '<img class="imageThumb" src="' + loadEvent.target.result + '" title="' + file.name + '"/>' +
                  '<br/><span class="remove"></span>' +
                "</div>"
              );
            };
            fileReader.readAsDataURL(file);
          }
        }

        // 更新input的files集合
        this.files = dataTransfer.files;
      });
    });
  } else {
    alert("您的浏览器不支持File API");
  }
});

修复要点

  1. 事件委托:使用$wrap.on("click", ".remove", function(){})代替重复绑定,只绑定一次事件,动态生成的.remove元素也能正常触发。
  2. 文件名匹配索引:删除时通过图片的title(即文件名)找到对应在files_name_arr中的索引,确保精准删除目标文件。
  3. 重构文件添加逻辑:将文件读取和渲染放在添加新文件的循环中,避免重复遍历已有文件,提升代码效率。
  4. 移除重复绑定逻辑:删掉原代码中在onloadend内对所有.remove元素的循环绑定,彻底解决点击一次触发多次的问题。

内容的提问来源于stack exchange,提问作者Duy Phi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 08:02:02