拖拽文件上传中Ajax进度监听器异常问题求助
如何正确实现XMLHttpRequest上传进度监听?
我明白你遇到的问题——上传进度监听要么没反应要么只触发一次,这在使用XMLHttpRequest做文件上传时是很常见的坑。咱们来一步步解决它:
先分析你之前尝试的问题
第一种尝试的错误:
request.upload = function(){console.log("me")}这完全不符合API规范:
request.upload是一个XMLHttpRequestUpload对象,不是可赋值的函数。你需要给这个对象添加事件监听器,而不是覆盖它。第二种尝试只触发一次的原因:
大概率是你添加监听器的时机不对——必须在调用request.open()之前(或者至少在request.send()之前)绑定upload的进度事件,否则浏览器可能已经开始发送数据,早期的进度事件会被错过。如果文件很小,浏览器瞬间发送完成,也会看起来只触发一次,可以用大文件测试验证。
修正后的完整代码
下面是调整后的拖拽上传代码,已经正确实现了上传进度监听:
(function(){ var dropzone = document.getElementById('dropzone'); var uploadFile = function (files) { var formData = new FormData(); var request = new XMLHttpRequest(); var totalSize = 0; // 遍历文件,添加到FormData并计算总大小 for(var i = 0; i < files.length; i++){ formData.append('file[]', files[i]); totalSize += files[i].size; } // 👉 关键:先绑定上传进度监听器,再执行open/send request.upload.addEventListener("progress", progressBar, false); // 上传完成后的处理 request.onload = function(){ if (this.status >= 200 && this.status < 300) { console.log('上传成功!'); // window.location.reload(); } else { console.error('上传失败,状态码:', this.status); } }; // 上传出错的处理 request.onerror = function() { console.error('上传请求发生错误,请检查网络或后端服务'); }; // 打开请求并发送数据 request.open('POST', 'dragNdrop.php?isNotSet=set'); request.send(formData); }; // 进度条更新函数 function progressBar(event){ // 确保浏览器能获取到总大小,避免计算错误 if (event.lengthComputable) { var percent = Math.round((event.loaded / event.total) * 100); console.log(`${percent}% | 已上传:${event.loaded}字节 | 总大小:${event.total}字节`); // 这里可以添加DOM操作来更新页面上的进度条,比如: // document.getElementById('progress-bar').style.width = percent + '%'; } } dropzone.ondragover = function(){ this.className = 'dropzone dragover'; return false; }; dropzone.ondragleave = function(){ this.className = 'dropzone'; return false; }; dropzone.ondrop = function (event) { event.preventDefault(); this.className = 'dropzone'; uploadFile(event.dataTransfer.files); return false; } }());
关键注意事项
- 监听器绑定顺序:必须先给
request.upload添加事件监听器,再调用request.open()和request.send(),否则会错过早期的进度事件。 - 检查
event.lengthComputable:有些情况下浏览器无法获取文件总大小(比如跨域或服务器返回的头信息问题),这时候event.total会是0,需要先判断再计算百分比,避免NaN错误。 - 大文件测试:如果测试用的文件太小,浏览器会瞬间完成上传,进度事件可能只触发一次,建议用几百MB的文件测试,就能看到多次进度更新。
- 后端兼容性:虽然前端进度是浏览器监控发送字节数,但如果后端启用了强制缓冲(比如PHP的
ob_start()),理论上不影响上传进度监听,但如果是后端处理上传的进度(比如接收文件的进度),那需要额外的后端配置,但前端的upload进度和这个无关。
内容的提问来源于stack exchange,提问作者user9697902
相关产品推荐
相关产品推荐

