原生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输入框,表单默认提交只会发送输入框内的文件。需将拖拽文件添加到输入框的文件列表中,保留表单默认提交逻辑即可解决。
修改步骤
- 添加全局数组跟踪所有选中的文件(包含点击选择和拖拽的)
- 更新
filesManager函数,将新文件加入全局数组,同时通过DataTransfer构造新的FileList赋值给隐藏输入框(因input的files属性只读,需用此方法更新) - 修正预览代码的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
相关产品推荐
相关产品推荐

