JavaScript:多次添加文件超上限时,如何在change事件中截取文件数组
解决分多次添加文件时的总数量限制问题
你的核心问题是当前代码仅对单次选择的文件做数量限制,但未考虑已存在的文件总数,导致分多次添加后总数量会超过10个。下面是具体的解决方案:
解决思路
- 先获取当前已选择的所有文件并转成数组
- 对新选择的文件进行去重(避免重复添加同名文件)
- 将现有文件与去重后的新文件合并,截取前10个确保总数不超限
- 重新构建
DataTransfer对象,同步到文件输入框和预览组件
修改后的关键代码
把attachFiles的change事件中的文件添加逻辑替换为以下代码:
attachFiles.addEventListener('change', (e) => { const MAX_FILES = 10; // 获取当前已提交的文件数组 const currentFiles = Array.from(submitData.files); // 新选择的文件去重:过滤掉已存在的同名文件 const newFiles = [...e.target.files].filter(file => currentFiles.every(curr => curr.name !== file.name) ); // 合并现有文件和新文件,截取前10个 const combinedFiles = [...currentFiles, ...newFiles].slice(0, MAX_FILES); // 清空原有submitData,重新添加截取后的文件 submitData.clear(); combinedFiles.forEach(file => submitData.items.add(file)); // 同步文件输入框的FileList attachFiles.files = submitData.files; // 生成新预览前清空previewWrapper previewWrapper.replaceChildren(); // 等待所有图片验证完成 Promise.allSettled(combinedFiles.map(showFiles)).then((results) => { // 检查是否有文件被舍弃,若有则提示用户 const totalAttempted = currentFiles.length + newFiles.length; if (totalAttempted > MAX_FILES) { // 示例:在页面顶部添加错误提示 const errorMsg = document.createElement('div'); errorMsg.style.color = 'red'; errorMsg.textContent = `已自动移除多余文件,最多支持上传${MAX_FILES}个文件,请查看预览列表`; document.body.insertBefore(errorMsg, document.body.firstChild); // 定时移除提示 setTimeout(() => errorMsg.remove(), 5000); } // 处理每个文件的验证结果 results.forEach((result, index) => { if (result.status === 'rejected') { console.log(`文件${combinedFiles[index].name}验证失败:`, result.reason); // 可给对应预览图添加错误标记 } }); }); });
代码说明
- 去重逻辑:通过
filter+every确保不会重复添加同名文件,和你原有逻辑保持一致 - 总数限制:合并后直接截取前10个,不管单次还是多次添加,最终总数都不会超限制
- 重构DataTransfer:因为
DataTransfer没有直接修改内容的API,所以需要先清空再重新添加文件 - 用户提示:通过对比尝试添加的总数量和最大限制,判断是否有文件被舍弃,进而给出友好提示
完整代码整合
const attachFiles = document.getElementById('attach-files'), dropZone = document.getElementById('dropzone'), previewWrapper = document.getElementById('preview-wrapper'), submitData = new DataTransfer(); dropZone.addEventListener('click', () => { attachFiles.click(); }); attachFiles.addEventListener('change', (e) => { const MAX_FILES = 10; const currentFiles = Array.from(submitData.files); const newFiles = [...e.target.files].filter(file => currentFiles.every(curr => curr.name !== file.name) ); const combinedFiles = [...currentFiles, ...newFiles].slice(0, MAX_FILES); submitData.clear(); combinedFiles.forEach(file => submitData.items.add(file)); attachFiles.files = submitData.files; previewWrapper.replaceChildren(); Promise.allSettled(combinedFiles.map(showFiles)).then((results) => { const totalAttempted = currentFiles.length + newFiles.length; if (totalAttempted > MAX_FILES) { const errorMsg = document.createElement('div'); errorMsg.style.color = 'red'; errorMsg.textContent = `已自动移除多余文件,最多支持上传${MAX_FILES}个文件,请查看预览列表`; document.body.insertBefore(errorMsg, document.body.firstChild); setTimeout(() => errorMsg.remove(), 5000); } results.forEach((result, index) => { if (result.status === 'rejected') { console.log(`文件${combinedFiles[index].name}验证失败:`, result.reason); } }); }); }); function showFiles(file) { return new Promise((resolve, reject) => { const previewImage = new Image(); const reader = new FileReader(); reader.onload = (e) => { previewImage.src = e.target.result; // 创建预览项 const previewItem = document.createElement('div'); previewItem.appendChild(previewImage); previewWrapper.appendChild(previewItem); // 执行decode验证 previewImage.decode() .then(() => { // 这里添加你的JS验证逻辑 resolve(); }) .catch(error => { console.log(`文件${file.name}解码失败:`, error); reject(error); }); }; reader.readAsDataURL(file); }); }
内容的提问来源于stack exchange,提问作者paulo77
相关产品推荐
相关产品推荐

