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

原生JS多图上传:手动选择正常,拖拽上传无法随表单提交

问题描述

基于某脚本实现表单多图上传,表单包含多个输入项。手动点击选择图片时文件可随表单正常提交,但拖拽图片到dropzone区域时,文件无法随表单提交。曾尝试在previewFile函数中添加以下代码,无效:

let dropBox = document.getElementById('dropBox');
let formData = new FormData(dropBox[0]);
formData.append('photos', file);

当前使用代码如下:

JS代码

let dropBox = document.getElementById('dropBox');

['dragenter', 'dragover', 'dragleave', 'drop'].forEach(evt => {
  dropBox.addEventListener(evt, prevDefault, false);
});

function prevDefault(e) {
  e.preventDefault();
  e.stopPropagation();
}
['dragenter', 'dragover'].forEach(evt => {
  dropBox.addEventListener(evt, hover, false);
});
['dragleave', 'drop'].forEach(evt => {
  dropBox.addEventListener(evt, unhover, false);
});

function hover(e) {
  dropBox.classList.add('!bg-lime-100', 'border-lime-300');
}

function unhover(e) {
  dropBox.classList.remove('!bg-lime-100', 'border-lime-300');
}

dropBox.addEventListener('drop', mngDrop, false);

function mngDrop(e) {
  let dataTrans = e.dataTransfer;
  let files = dataTrans.files;
  filesManager(files);
}

function filesManager(files) {
  files = [...files];
  files.forEach(previewFile);
}

function previewFile(file) {
  if (!file.type.match(/image.*/)) {
    return alert('Only JPG, JPEG and PNG files are allowed');
  }

  let fReader = new FileReader();
  let gallery = document.getElementById('gallery');

  fReader.readAsDataURL(file);

  fReader.onloadend = function() {
    let wrap = document.createElement('div');
    let img = document.createElement('img');

    img.src = fReader.result;
    img.classList.add('rounded-lg');

    let imgCapt = document.createElement('p');

    let fSize = Math.round((file.size / 1024 / 1024) * 10) / 10 + ' MB';

    imgCapt.innerHTML = `<span class="text-md font-bold tracking-tight">${fSize}</span>`;
    gallery.appendChild(wrap).appendChild(img);
    gallery.appendChild(wrap).appendChild(imgCapt);
  }
}

HTML代码

<form method="post" action="..." enctype="multipart/form-data">

  <input type="text" name="name">
  <input type="text" name="example">
  <input type="text" name="etc">

  <div id="dropBox" class="border-2 border-dashed bg-white border-slate-300 rounded-lg md:p-5 p-10 text-center">
    <p class="mb-2 mt-4">Drag and drop your images here, or</p>
    <input type="file" name="photos[]" id="imgUpload" multiple accept="image/*" onchange="filesManager(this.files)" class="hidden">
    <label for="imgUpload" class="block mt-4 font-bold cursor-pointer"><u>Click here</u> to select from your computer</label>
    <div id="gallery" class="mt-4 grid grid-cols-2 md:grid-cols-3 gap-4"></div>
  </div>

</form>
解决方案

核心问题:拖拽的文件未关联到表单的file输入框,表单默认提交只会发送输入框内的文件。需将拖拽文件添加到输入框的文件列表中,保留表单默认提交逻辑即可解决。

修改步骤

  1. 添加全局数组跟踪所有选中的文件(包含点击选择和拖拽的)
  2. 更新filesManager函数,将新文件加入全局数组,同时通过DataTransfer构造新的FileList赋值给隐藏输入框(因input的files属性只读,需用此方法更新)
  3. 修正预览代码的DOM操作错误,避免重复添加容器元素

修改后的完整JS代码

let dropBox = document.getElementById('dropBox');
const imgUploadInput = document.getElementById('imgUpload');
// 全局数组存储所有选中的文件
let selectedFiles = [];

['dragenter', 'dragover', 'dragleave', 'drop'].forEach(evt => {
  dropBox.addEventListener(evt, prevDefault, false);
});

function prevDefault(e) {
  e.preventDefault();
  e.stopPropagation();
}
['dragenter', 'dragover'].forEach(evt => {
  dropBox.addEventListener(evt, hover, false);
});
['dragleave', 'drop'].forEach(evt => {
  dropBox.addEventListener(evt, unhover, false);
});

function hover(e) {
  dropBox.classList.add('!bg-lime-100', 'border-lime-300');
}

function unhover(e) {
  dropBox.classList.remove('!bg-lime-100', 'border-lime-300');
}

dropBox.addEventListener('drop', mngDrop, false);

function mngDrop(e) {
  let dataTrans = e.dataTransfer;
  let files = dataTrans.files;
  filesManager(files);
}

function filesManager(files) {
  // 将新文件加入全局数组
  selectedFiles = [...selectedFiles, ...files];
  
  // 构造新的FileList并赋值给输入框,让表单能识别拖拽的文件
  const dataTransfer = new DataTransfer();
  selectedFiles.forEach(file => {
    dataTransfer.items.add(file);
  });
  imgUploadInput.files = dataTransfer.files;
  
  // 预览新添加的文件
  [...files].forEach(previewFile);
}

function previewFile(file) {
  if (!file.type.match(/image.*/)) {
    return alert('Only JPG, JPEG and PNG files are allowed');
  }

  let fReader = new FileReader();
  let gallery = document.getElementById('gallery');

  fReader.readAsDataURL(file);

  fReader.onloadend = function() {
    let wrap = document.createElement('div');
    let img = document.createElement('img');

    img.src = fReader.result;
    img.classList.add('rounded-lg');

    let imgCapt = document.createElement('p');
    let fSize = Math.round((file.size / 1024 / 1024) * 10) / 10 + ' MB';
    imgCapt.innerHTML = `<span class="text-md font-bold tracking-tight">${fSize}</span>`;
    
    // 先将元素加入容器,再统一添加到页面
    wrap.appendChild(img);
    wrap.appendChild(imgCapt);
    gallery.appendChild(wrap);
  }
}

说明

  • 全局数组selectedFiles统一管理所有文件,如需避免重复上传可额外添加去重逻辑
  • 通过DataTransfer构造的FileList会被表单识别,提交时自动包含所有拖拽和选择的文件
  • 修正了原预览代码中重复添加容器的错误,保证DOM结构正确

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 02:41:03