Django异步表单上传进度条失效问题排查求助
问题描述
我正在为Django网站的异步表单添加上传进度条,此前功能正常,但近期进度条不再显示上传进度。怀疑是作用域错误,但不确定如何修复。相关代码如下:
HTML模板代码
{% extends "base.html" %} {% load crispy_forms_tags %} {% block content %} <form id="post-form" method="POST" enctype="multipart/form-data"> {% csrf_token %} <fieldset class="form-group"> <legend class="border-bottom mb-4">Post <p style="text-align: right;"> <a class="btn btn-outline-primary" href="{% url 'photobooth:photobooth' %}">Booth</a> {% if not request.GET.schedule %}<a class="btn btn-outline-success" href="?schedule=t{% if request.GET.camera %}&camera=t{% endif %}{% if request.GET.audio %}&audio=t{% endif %}"><i class="bi bi-calendar-fill"></i></a>{% endif %} {% if not request.GET.camera %}<a class="btn btn-outline-primary" href="?camera=t{% if request.GET.schedule %}&schedule=t{% endif %}{% if request.GET.audio %}&audio=t{% endif %}"><i class="bi bi-camera-fill"></i></a>{% endif %} {% if not request.GET.audio %}<a class="btn btn-outline-danger" href="?audio=t{% if request.GET.camera %}&camera=t{% endif %}{% if request.GET.schedule %}&schedule=t{% endif %}"><i class="bi bi-mic-fill"></i></a>{% endif %} </p> </legend> {{ form|crispy }} </fieldset> <div id="uploaded_image"></div> <hr> <p id="contentLength"></p> <div id="progressBars"></div> <div class="form-group"> <button class="btn btn-outline-info" type="submit">Post</button> </div> <p style="text-color: green;" class="hide" id="posted">Your post has been submitted.</p> </form> {% endblock content %}
JavaScript代码
var form = document.getElementById("post-form"); var posted = document.getElementById("posted"); var chooseFile = document.getElementById("id_image"); var imgPreview = document.getElementById("uploaded_image"); var counter = 0; $(form).submit(function(e){ e.preventDefault(); form = document.getElementById("post-form"); var formData = new FormData(form); form.reset(); imgPreview.innerHTML = ""; $("#progressBars").append('<progress id="progress' + counter + '" value="0" max="100" style="width: 100%">0%</progress>'); var progress = document.getElementById("progress" + counter); counter++; $.ajax({ xhr: function() { var xhr = new window.XMLHttpRequest(); xhr.upload.counter = counter; xhr.counter = counter; xhr.upload.addEventListener("progress", function(evt) { if (evt.lengthComputable) { var percentComplete = evt.loaded / evt.total; percentComplete = parseInt(percentComplete * 100); var progressBar = document.getElementById("progress" + evt.target.counter); progressBar.innerHTML = percentComplete + '%'; progressBar.value = percentComplete; } }); return xhr; }, url: window.location.pathname, type: "POST", data: formData, cache: false, contentType: false, processData: false, timeout: 1000 * 60 * 30, success: function(data) { $(posted).toggleClass("hide"); setTimeout(function() { $(posted).toggleClass("fade-hidden"); $(progress).toggleClass("fade-hidden"); setTimeout(function() { $(posted).toggleClass("hide"); $(posted).toggleClass("fade-hidden"); $(progress).toggleClass("hide"); $(progress).toggleClass("fade-hidden"); }, 2000); }, 2000); }, }); }); chooseFile.addEventListener("change", function () { getImgData(); }); function getImgData() { const files = chooseFile.files[0]; if (files) { const fileReader = new FileReader(); fileReader.readAsDataURL(files); fileReader.addEventListener("load", function () { imgPreview.style.display = "block"; imgPreview.innerHTML = '<img width="100%" src="' + this.result + '" />'; }); } }
我也曾尝试移除progressBar变量,改用progress变量,但仍未解决问题。这是否与浏览器更新有关?我哪里操作失误或遗漏了什么?
修复方案
核心问题:计数器值不匹配
你代码里的关键错误是计数器赋值时机错误:
- 创建进度条时用的是当前
counter值(比如0) - 紧接着执行
counter++,此时counter变成1 - 然后给
xhr.upload.counter赋值为1 - 进度事件触发时,用
evt.target.counter(值为1)去找progress1元素,但实际存在的是progress0,自然找不到元素,进度条也就不会更新
修复步骤:
- 保存当前计数器值:在
counter++之前,把当前的counter值存到一个变量里,避免后续自增影响 - 正确绑定进度条到XHR对象:用保存的变量给
xhr.upload.counter赋值 - 可选优化:直接把进度条元素绑定到XHR对象,省去ID查找步骤,同时增加元素存在判断,避免报错
修改后的JavaScript关键部分:
$(form).submit(function(e){ e.preventDefault(); form = document.getElementById("post-form"); var formData = new FormData(form); form.reset(); imgPreview.innerHTML = ""; // 保存当前counter值,避免自增后变化 var currentCounter = counter; $("#progressBars").append('<progress id="progress' + currentCounter + '" value="0" max="100" style="width: 100%">0%</progress>'); var progress = document.getElementById("progress" + currentCounter); counter++; $.ajax({ xhr: function() { var xhr = new window.XMLHttpRequest(); // 绑定当前的计数器值到upload对象 xhr.upload.counter = currentCounter; // 直接绑定进度条元素,省去ID查找 xhr.upload.progressBar = progress; xhr.upload.addEventListener("progress", function(evt) { if (evt.lengthComputable) { var percentComplete = evt.loaded / evt.total; percentComplete = parseInt(percentComplete * 100); // 获取进度条元素,增加存在判断 var progressBar = evt.target.progressBar || document.getElementById("progress" + evt.target.counter); if(progressBar){ progressBar.innerHTML = percentComplete + '%'; progressBar.value = percentComplete; } } }); return xhr; }, // 其余代码保持不变 }); });
额外检查点:
- 确认服务器端未开启Gzip压缩:如果开启压缩,
evt.total无法正确计算,会导致lengthComputable为false,进度条无法更新 - 浏览器更新一般不会影响XHR的progress事件,可测试不同浏览器排除兼容性问题
- 打开浏览器控制台(F12),查看是否有"找不到元素"的报错,快速定位问题
内容的提问来源于stack exchange,提问作者Charlotte Harper
相关产品推荐
相关产品推荐

