JavaScript中如何分别获取每个上传文件的已加载量与总量?
解决多文件上传时单个文件进度条同步的问题
嗨,我来帮你搞定这个问题!你遇到的情况其实很常见:单个文件上传时进度条正常,但多文件一起传就全部同步,核心问题在于你可能把所有文件塞进了同一个请求里,导致进度事件返回的是整个请求的总进度,而不是单个文件的。
要实现每个文件单独的进度追踪,我们需要给每个文件创建独立的上传请求,同时为每个文件绑定专属的进度条元素。下面是具体的解决思路和代码示例:
问题根源拆解
如果你的代码是把所有文件添加到同一个FormData,然后用同一个XMLHttpRequest发送,那么progress事件里的e.loaded和e.total对应的是整个请求的上传数据量,自然所有进度条都会显示相同的数值。
解决方案:每个文件单独发起上传请求
我们可以遍历文件列表,为每个文件创建独立的FormData和XMLHttpRequest,同时为每个文件生成专属的进度条DOM,这样每个请求的进度事件就能精准对应到单个文件的进度。
第一步:HTML结构准备
先准备好文件选择器(开启multiple支持多选)和进度条容器:
<input type="file" id="plik" multiple> <button onclick="uploadFiles()">开始上传所有文件</button> <div id="progressContainer"></div>
第二步:JavaScript实现
// 简化DOM获取的工具函数 function _(el) { return document.getElementById(el); } function uploadFiles() { const files = _("plik").files; const progressContainer = _("progressContainer"); // 清空之前的进度条(可选) progressContainer.innerHTML = ''; // 遍历每个选中的文件 for (let i = 0; i < files.length; i++) { const currentFile = files[i]; // 为当前文件创建专属的进度条DOM元素 const fileProgressWrapper = document.createElement('div'); fileProgressWrapper.style.margin = '10px 0'; fileProgressWrapper.innerHTML = ` <p>正在上传:${currentFile.name}</p> <div style="width: 100%; height: 24px; background-color: #e0e0e0; border-radius: 4px; overflow: hidden;"> <div class="progress-bar" style="width: 0%; height: 100%; background-color: #2196F3; transition: width 0.2s ease;"></div> </div> <span class="progress-text">0%</span> `; progressContainer.appendChild(fileProgressWrapper); // 获取当前文件对应的进度条和文本元素 const progressBar = fileProgressWrapper.querySelector('.progress-bar'); const progressText = fileProgressWrapper.querySelector('.progress-text'); // 创建仅包含当前文件的FormData const formData = new FormData(); formData.append('plik', currentFile); // 这里的键名要和后端接口保持一致 // 创建独立的XMLHttpRequest对象 const xhr = new XMLHttpRequest(); xhr.open('POST', '你的后端上传接口地址', true); // 绑定上传进度事件 xhr.upload.addEventListener('progress', function(e) { if (e.lengthComputable) { // 计算当前文件的上传进度:已加载字节数 / 文件总字节数 * 100 const percent = Math.round((e.loaded / e.total) * 100); progressBar.style.width = `${percent}%`; progressText.textContent = `${percent}%`; } }); // 上传完成后的处理 xhr.onload = function() { if (xhr.status === 200) { progressText.textContent = '上传完成 ✅'; progressBar.style.backgroundColor = '#4CAF50'; } else { progressText.textContent = '上传失败 ❌'; progressBar.style.backgroundColor = '#F44336'; } }; // 上传出错的处理 xhr.onerror = function() { progressText.textContent = '上传出错 ❌'; progressBar.style.backgroundColor = '#F44336'; }; // 发送当前文件的上传请求 xhr.send(formData); } }
关键细节说明
- 每个文件对应独立的
XMLHttpRequest:这样每个请求的upload.progress事件只会返回当前文件的上传数据,e.loaded是该文件已上传的字节数,e.total是该文件的总大小,完美实现单个文件的进度追踪。 - 专属进度条DOM:为每个文件动态生成进度条元素,确保进度更新时能精准修改对应的DOM,不会互相干扰。
- 如果一定要用单个请求上传多文件:这种情况下原生XHR无法区分单个文件的进度,需要后端配合返回每个文件的上传状态,实现起来复杂很多,所以更推荐单个文件单独请求的方案。
内容的提问来源于stack exchange,提问作者Sławcio
相关产品推荐
相关产品推荐

