You need to enable JavaScript to run this app. 原生JavaScript为多图上传预览添加图片移除选项
优惠活动
大模型
产品
解决方案
定价
更多

原生JavaScript为多图上传预览添加图片移除选项

纯原生多图上传删除功能实现方案

核心约束说明

原生DOM提供的input.files返回的是只读FileList结构,没有提供直接删除单文件的接口,因此需要通过自定义维护可变文件数组的方式实现删除逻辑,全程不需要依赖jQuery。

实现思路

  • 单独维护一个可变的文件数组,作为实际待上传的数据源,替代只读的原生FileList
  • 渲染预览时遍历自定义数组,为每个预览项绑定对应文件的删除按钮
  • 点击删除按钮时,从自定义数组中移除匹配的文件对象,再触发预览重新渲染
  • 表单提交前,通过DataTransfer对象将过滤后的自定义数组同步为input的files属性,确保被删除的文件不会随表单提交到服务端

完整改造代码

改造后的JavaScript逻辑

// 自定义维护的待上传文件数组(替代只读的原生FileList)
let selectedFiles = [];
const input = document.querySelector('input');
const preview = document.querySelector('.preview');

input.style.opacity = 0;

// 文件选择回调
input.addEventListener('change', (e) => {
  // 将新选择的文件追加到自定义数组,不会覆盖之前已选的文件
  const newSelected = Array.from(e.target.files);
  selectedFiles = [...selectedFiles, ...newSelected];
  // 重新渲染预览
  updateImageDisplay();
});

// 表单提交前同步过滤后的文件到input元素
document.querySelector('form').addEventListener('submit', () => {
  const dataTransfer = new DataTransfer();
  selectedFiles.forEach(file => dataTransfer.items.add(file));
  // 赋值后,表单提交时只会携带经过删除筛选的文件
  input.files = dataTransfer.files;
});

function updateImageDisplay() {
  // 清空预览区域
  while(preview.firstChild) {
    preview.removeChild(preview.firstChild);
  }

  if(selectedFiles.length === 0) {
    const para = document.createElement('p');
    para.textContent = 'No files currently selected for upload';
    preview.appendChild(para);
    return;
  }

  const list = document.createElement('ol');
  preview.appendChild(list);

  for(const file of selectedFiles) {
    const listItem = document.createElement('li');
    const para = document.createElement('p');

    // 通用删除按钮生成逻辑
    const deleteBtn = document.createElement('button');
    deleteBtn.textContent = '删除';
    deleteBtn.className = 'delete-btn';
    deleteBtn.addEventListener('click', () => {
      // 按文件对象引用匹配删除,同名同大小文件也不会误删
      selectedFiles = selectedFiles.filter(item => item !== file);
      // 重新渲染预览
      updateImageDisplay();
    });

    if(validFileType(file)) {
      para.textContent = `File name ${file.name}, file size ${returnFileSize(file.size)}.`;
      const image = document.createElement('img');
      image.src = URL.createObjectURL(file);

      listItem.appendChild(image);
      listItem.appendChild(para);
    } else {
      para.textContent = `File name ${file.name}: Not a valid file type. Update your selection.`;
    }

    // 不管是有效图片还是无效文件,都加上删除按钮
    listItem.appendChild(deleteBtn);
    list.appendChild(listItem);
  }
}

const fileTypes = [
  'image/apng',
  'image/bmp',
  'image/gif',
  'image/jpeg',
  'image/pjpeg',
  'image/png',
  'image/svg+xml',
  'image/tiff',
  'image/webp',
  'image/x-icon'
];

function validFileType(file) {
  return fileTypes.includes(file.type);
}

function returnFileSize(number) {
  if(number < 1024) {
    return number + 'bytes';
  } else if(number >= 1024 && number < 1048576) {
    return (number/1024).toFixed(1) + 'KB';
  } else if(number >= 1048576) {
    return (number/1048576).toFixed(1) + 'MB';
  }
}

适配的CSS样式

form {
  width: 600px;
  background: #ccc;
  margin: 0 auto;
  padding: 20px;
  border: 1px solid black;
}

form ol {
  padding-left: 0;
}

form li, div > p {
  background: #eee;
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
  list-style-type: none;
  border: 1px solid black;
}

form img {
  height: 64px;
  order: 1;
}

form p {
  line-height: 32px;
  padding-left: 10px;
}

/* 新增:删除按钮对齐样式 */
form .delete-btn {
  align-self: center;
  margin-right: 10px;
}

form label, form button {
  background-color: #7F9CCB;
  padding: 5px 10px;
  border-radius: 5px;
  border: 1px ridge black;
  font-size: 0.8rem;
  height: auto;
}

form label:hover, form button:hover {
  background-color: #2D5BA3;
  color: white;
}

form label:active, form button:active {
  background-color: #0D3F8F;
  color: white;
}

原有HTML结构无需额外修改

<form>
  <div>
    <label for="image_uploads">Choose images to upload (PNG, JPG)</label>
    <input type="file" id="image_uploads" name="image_uploads" accept=".jpg, .jpeg, .png" multiple>
  </div>
  <div class="preview">
    <p>No files currently selected for upload</p>
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>

实现注意点

  • 删除时通过文件对象引用匹配,不需要依赖文件名、大小等可能重复的字段,不会出现删错项的问题
  • DataTransfer对象兼容所有现代浏览器,不需要引入额外依赖
  • 支持多次选择文件追加的场景,不会因为重新选文件覆盖之前已选中的待上传文件
  • 无效格式的文件也可以通过删除按钮移除,不会卡在预览列表里
  • 如需优化内存占用,可在删除对应预览项时,调用URL.revokeObjectURL(预览img的src)释放Blob内存

内容的提问来源于stack exchange,提问作者1878castle

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.23 11:24:04