我有一个允许用户下载动态生成文件的页面。生成它需要很长时间,所以我想显示一个“等待”指示器。问题是,我不知道如何检测浏览器何时接收到文件,以便我可以隐藏指示器。
我请求一个隐藏的表单,它post到服务器,并以一个隐藏的iframe作为其结果的目标。这样我就不会用结果替换整个浏览器窗口。我监听iframe上的“load”事件,希望它在下载完成时触发。
我将文件返回一个“Content-Disposition: attachment”头,这将导致浏览器显示“Save”对话框。但是浏览器不会在iframe中触发“load”事件。
我尝试过的一种方法是采用多部分回答。所以它会发送一个空的HTML文件,以及附加的可下载文件。
例如:
Content-type: multipart/x-mixed-replace;boundary="abcde"
--abcde
Content-type: text/html
--abcde
Content-type: application/vnd.fdf
Content-Disposition: attachment; filename=foo.fdf
file-content
--abcde
这在Firefox中是有效的;它接收空HTML文件,触发“load”事件,然后显示可下载文件的“Save”对话框。但它在ie和Safari浏览器上无法运行;Internet Explorer触发“load”事件,但它不下载文件,而Safari下载文件(带有错误的名称和内容类型),但不触发“load”事件。
另一种方法可能是调用启动文件创建,轮询服务器直到准备就绪,然后下载已经创建的文件。但我宁愿避免在服务器上创建临时文件。
我该怎么办?
我使用以下代码下载blobs并在下载后撤销对象URL。它在Chrome和Firefox中工作!
function download(blob){
var url = URL.createObjectURL(blob);
console.log('create ' + url);
window.addEventListener('focus', window_focus, false);
function window_focus(){
window.removeEventListener('focus', window_focus, false);
URL.revokeObjectURL(url);
console.log('revoke ' + url);
}
location.href = url;
}
关闭文件下载对话框后,窗口将获得其焦点,因此将触发焦点事件。
当按钮/链接被单击时创建一个iframe,并将其附加到body。
$('<iframe />')
.attr('src', url)
.attr('id', 'iframe_download_report')
.hide()
.appendTo('body');
创建一个延迟的iframe,下载后删除。
var triggerDelay = 100;
var cleaningDelay = 20000;
var that = this;
setTimeout(function() {
var frame = $('<iframe style="width:1px; height:1px;" class="multi-download-frame"></iframe>');
frame.attr('src', url + "?" + "Content-Disposition: attachment ; filename=" + that.model.get('fileName'));
$(ev.target).after(frame);
setTimeout(function() {
frame.remove();
}, cleaningDelay);
}, triggerDelay);