如何在jQuery和Laravel中实现单输入框多图/文件上传及预览
多文件上传(支持预览、取消)实现方案
基于你提供的HTML结构,我们可以通过JavaScript结合CSS来实现多文件预览和取消功能,核心思路是用数组维护选中的文件(原生FileList不可修改),为每个文件生成预览项并绑定删除事件。
1. 补充CSS样式
先添加必要的样式,让预览区域和取消按钮正常显示:
.upload__img-wrap { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 15px; } .upload__img-box { position: relative; width: 120px; height: 120px; border: 1px solid #eee; border-radius: 4px; overflow: hidden; } .upload__img-box img, .upload__pdf-icon { width: 100%; height: 100%; object-fit: cover; display: flex; align-items: center; justify-content: center; background-color: #f5f5f5; font-size: 14px; color: #666; } .upload__img-close { position: absolute; top: 5px; right: 5px; width: 20px; height: 20px; border-radius: 50%; background-color: rgba(0,0,0,0.6); color: #fff; border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 12px; }
2. JavaScript核心逻辑
添加以下脚本,实现文件选择、预览生成、取消删除功能:
// 获取DOM元素 const fileInput = document.getElementById('files'); const previewWrap = document.querySelector('.upload__img-wrap'); // 用数组维护选中的文件(原生FileList不可修改) let selectedFiles = []; // 监听文件选择事件 fileInput.addEventListener('change', function(e) { const files = Array.from(e.target.files); // 过滤已选中的文件(避免重复添加) const newFiles = files.filter(file => !selectedFiles.some(existFile => existFile.name === file.name && existFile.size === file.size)); selectedFiles = [...selectedFiles, ...newFiles]; // 生成预览 renderPreviews(); // 清空原生input的文件列表,避免重复选择同一文件时不触发change事件 fileInput.value = ''; }); // 生成预览项函数 function renderPreviews() { previewWrap.innerHTML = ''; selectedFiles.forEach((file, index) => { const imgBox = document.createElement('div'); imgBox.className = 'upload__img-box'; // 区分图片和PDF文件 if (file.type.startsWith('image/')) { const img = document.createElement('img'); img.src = URL.createObjectURL(file); img.alt = file.name; imgBox.appendChild(img); } else if (file.type === 'application/pdf') { const pdfIcon = document.createElement('div'); pdfIcon.className = 'upload__pdf-icon'; pdfIcon.innerHTML = 'PDF<br>' + file.name; imgBox.appendChild(pdfIcon); } // 添加取消按钮 const closeBtn = document.createElement('button'); closeBtn.className = 'upload__img-close'; closeBtn.innerHTML = '×'; closeBtn.addEventListener('click', () => { // 移除预览项 imgBox.remove(); // 从数组中删除对应文件 selectedFiles.splice(index, 1); // 释放Blob URL,避免内存泄漏 if (file.type.startsWith('image/')) { URL.revokeObjectURL(img.src); } }); imgBox.appendChild(closeBtn); previewWrap.appendChild(imgBox); }); } // 表单提交时,将数组中的文件添加到FormData document.querySelector('form').addEventListener('submit', function(e) { e.preventDefault(); const formData = new FormData(this); // 清空原有的files[]字段 formData.delete('files[]'); // 添加数组中的文件 selectedFiles.forEach(file => { formData.append('files[]', file); }); // 这里可以发送AJAX请求,或者继续表单提交 // 示例:fetch('/upload', { method: 'POST', body: formData }) });
关键说明
- 用
selectedFiles数组维护选中的文件,解决原生FileList无法修改的问题 - 预览图片时使用
URL.createObjectURL生成临时链接,删除时记得用URL.revokeObjectURL释放内存 - 重复选择同一文件时,通过清空
fileInput.value确保change事件能触发 - PDF文件显示自定义的预览区域,也可以根据需求替换为PDF图标
- 表单提交时,需要手动将数组中的文件添加到FormData,替换原生的文件列表
内容的提问来源于stack exchange,提问作者Denis S Maheshwari
相关产品推荐
相关产品推荐

