【发布时间】:2020-06-11 02:56:29
【问题描述】:
在我的网页上,当用户单击下载按钮时,控制器会调用导出操作,生成一个 Excel 文件,然后将其返回给用户。根据传递给操作的参数,有时需要一些时间来生成文件并将其返回给用户。
所以,我想在等待文件时显示一个忙碌指示符。我选择了 Bootstrap 微调器。
$('.content').on('click', 'a.export', function (e) {
e.preventDefault();
// show busy indicator
$('#divSpinner').css('display', 'inline-block');
var idSelect = '';
$('#ddlSelect option:selected').each(function () {
idSelect += $('#ddlSelect')[0].value;
});
var idSelect2 = '';
$('#ddlSelect2 option:selected').each(function () {
idSelect2 += $('#ddlSelect2')[0].value;
});
var url = 'Home/Exports?' + 'param1=' + idSelect + '¶m2=' + idSelect2;
//download file
window.location = url;
// hide busy indicator
$('#divSpinner').css('display', 'none');
});
好吧,这种方法有效,但问题是 $('#divSpinner').css('display', 'none'); 立即被击中,并且微调器隐藏在文件之前实际可供用户下载(浏览器下载/打开窗口)。
如何重写代码以等待 window.location=url 完成然后隐藏微调器?
编辑: 我还尝试将下载部分包装在这样的异步函数中:
async function Download(url) {
let promise = new Promise((resolve, reject) => {
resolve(window.location = url);
});
let result = await promise; // wait until the promise resolves (*)
}
并这样称呼它:
Download(url)
.then(function() {
$('#divSpinner').hide()
});
下载有效,但在文件下载呈现给用户之前,$('#divSpinner').hide() 仍然被点击。 async/await 的全部意义不在于在继续执行代码之前等待结果吗??
EDIT2(带有“blob”):
async function Download(url) {
let promise = new Promise((resolve, reject) => {
resolve(filedownload(url));
});
let result = await promise;
}
function filedownload(urlToSend) {
var req = new XMLHttpRequest();
req.open("GET", urlToSend, true);
req.responseType = "blob";
req.onload = function (event) {
var blob = req.response;
var fileName = req.getResponseHeader("fileName")
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
};
req.send();
}
并这样称呼它:
Download(url)
.then(function() {
$('#divSpinner').hide()
});
编辑 3:我从下面使用了 @Nenad 的解决方案,但我只更改了响应标头的处理(否则我在下载时得到 NULL 文件名 - 我使用了这个解决方案 https://stackoverflow.com/a/40940790/7975627) :
function filedownload(urlToSend, resolve) {
var req = new XMLHttpRequest();
req.open("GET", urlToSend, true);
req.responseType = "blob";
req.onload = function (event) {
var blob = req.response;
var filename = "";
var disposition = req.getResponseHeader('Content-Disposition');
if (disposition && disposition.indexOf('attachment') !== -1) {
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
filename = matches[1].replace(/['"]/g, '');
}
}
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = filename;
link.click();
resolve(filename); // call resolve after download has finished.
};
req.send();
}
【问题讨论】:
-
这个函数是从同一个页面调用的吗?从 /Home/Exports ?
-
顺便说一下,你的
不起作用。因为您正在更改它之前的页面。所以我想你需要让你的指标在启动时可见。当excel数据出现时,您将隐藏指标。 -
是的,View 和 Controller 都是“Home”(Action Exports 也在 Home 控制器中)。 javascript/jquery 也是主视图的“Index.cshtml”的一部分
-
@cbalakus:。问题是它很快就被隐藏了(实际上是立即隐藏,因为代码不会在“window.location”处停止而是继续到最后,在文件准备好后提示用户保存/oen)
标签: javascript jquery async-await