Excel下载完成后如何隐藏jQuery Spinner?附代码求助
解决下载Excel后jQuery Spinner无法自动隐藏的问题
问题背景
你现在碰到的情况是:用户点击JSP页面里的Download提交按钮时,jQuery Spinner能正常显示,但当Servlet生成完Excel文件触发浏览器下载后,Spinner就一直停留在页面上不会自动隐藏,对吧?
问题原因
这是因为同步表单提交的特性导致的:当你点击submit按钮提交表单时,浏览器会发起同步请求,此时页面的JS线程会被阻塞,而且浏览器处理文件下载的过程并不会触发页面的任何“完成”回调——因为下载是浏览器的独立行为,不会刷新当前页面,所以你的JS代码没有机会去隐藏Spinner。
解决方案
这里给你两种可行的方案,你可以根据自己的项目情况选择:
方案一:改用AJAX请求+Blob处理下载(推荐)
这种方法通过AJAX异步请求Servlet,拿到Excel文件的二进制数据后,前端手动触发下载,这样就能监听请求的完成事件,在下载完成后隐藏Spinner。
1. 修改JSP中的按钮(把submit改成普通button)
<tr> <td> <br /> <br /> <input type="submit" value="Search" name="action" /> <input type="hidden" id="download_token_value_id" /> <!-- 把submit改成button,避免默认表单提交 --> <input type="button" value="Download" name="action" class="spinner" /> </td> </tr> <center> <div id="fontSpinner" style="color: blue; display: none;" class="fa fa-spinner fa-pulse fa-3x fa-fw"> </div> </center>
2. 修改JS代码,用AJAX处理请求和下载
$('.spinner').click(function() { $("#fontSpinner").css("display", "block"); // 显示Spinner // 发起AJAX请求 $.ajax({ url: "你的Servlet实际路径", // 替换成你的Servlet路径 type: "POST", // 或GET,根据你的Servlet配置调整 data: $("form").serialize(), // 序列化表单数据,保证参数和原提交一致 xhrFields: { responseType: 'blob' // 指定响应类型为二进制Blob }, success: function(blob, status, xhr) { // 从响应头获取文件名(如果Servlet设置了自定义头) const fileName = decodeURIComponent(xhr.getResponseHeader('X-File-Name')) || "导出数据.xlsx"; // 创建下载链接 const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = fileName; document.body.appendChild(a); a.click(); // 清理临时资源 window.URL.revokeObjectURL(url); document.body.removeChild(a); // 下载完成后隐藏Spinner $("#fontSpinner").css("display", "none"); }, error: function() { // 请求失败也要隐藏Spinner,避免一直显示 $("#fontSpinner").css("display", "none"); alert("下载失败,请重试!"); } }); });
3. (可选)修改Servlet添加自定义文件名头
如果想让前端动态获取文件名,可以在Servlet里添加:
response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("UTF-8"); String excelFileName = "导出数据.xlsx"; response.setHeader("Content-Disposition", "attachment; filename=\"" + excelFileName + "\""); // 添加自定义头,方便前端获取文件名 response.setHeader("X-File-Name", URLEncoder.encode(excelFileName, "UTF-8")); // 生成Excel文件的代码... ServletOutputStream out = response.getOutputStream(); workbook.write(out); workbook.close(); out.flush(); out.close();
方案二:用Cookie轮询实现(适合不想改AJAX的场景)
如果你的项目不适合改用AJAX,可以让Servlet在完成Excel输出后设置一个Cookie,前端用定时器轮询这个Cookie,一旦检测到就隐藏Spinner并清除Cookie。
1. 修改Servlet代码,添加Cookie
// 生成并输出Excel的代码... workbook.write(out); workbook.close(); out.flush(); out.close(); // 添加Cookie标记下载完成 Cookie downloadComplete = new Cookie("download_complete", "true"); downloadComplete.setPath("/"); // 路径要和项目一致 downloadComplete.setMaxAge(10); // 10秒后自动过期 response.addCookie(downloadComplete);
2. 修改JS代码,添加轮询逻辑
$('.spinner').click(function() { $("#fontSpinner").css("display", "block"); // 显示Spinner // 启动定时器每500毫秒检查一次Cookie const checkCookieInterval = setInterval(function() { const cookies = document.cookie.split(';'); let isDownloadDone = false; // 遍历Cookie查找标记 for(let cookie of cookies) { const [name, value] = cookie.trim().split('='); if(name === 'download_complete' && value === 'true') { isDownloadDone = true; break; } } if(isDownloadDone) { // 隐藏Spinner $("#fontSpinner").css("display", "none"); // 清除Cookie document.cookie = "download_complete=; path=/; max-age=0"; // 停止轮询 clearInterval(checkCookieInterval); } }, 500); });
注意事项
- 方案一中,要确保表单的所有参数都通过
$("form").serialize()正确传递,否则可能导致生成的Excel数据不符合预期。 - 方案二中,Cookie的路径要和你的项目根路径一致,否则前端可能无法获取到Cookie。
- 两种方案都要处理请求失败的情况,避免Spinner一直停留在页面上。
内容的提问来源于stack exchange,提问作者Saroj
相关产品推荐
相关产品推荐

