我有一个允许用户下载动态生成文件的页面。生成它需要很长时间,所以我想显示一个“等待”指示器。问题是,我不知道如何检测浏览器何时接收到文件,以便我可以隐藏指示器。
我请求一个隐藏的表单,它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”事件。
另一种方法可能是调用启动文件创建,轮询服务器直到准备就绪,然后下载已经创建的文件。但我宁愿避免在服务器上创建临时文件。
我该怎么办?
基于Elmer的例子,我准备了自己的解决方案。单击具有定义的“download”类的项目后,浏览器窗口中将显示一条自定义消息。我用焦点触发器隐藏了消息。我用焦点触发器隐藏了消息。
JavaScript
$(function(){$('.download').click(function() { ShowDownloadMessage(); }); })
function ShowDownloadMessage()
{
$('#message-text').text('Your report is creating. Please wait...');
$('#message').show();
window.addEventListener('focus', HideDownloadMessage, false);
}
function HideDownloadMessage(){
window.removeEventListener('focus', HideDownloadMessage, false);
$('#message').hide();
}
HTML
<div id="message" style="display: none">
<div id="message-screen-mask" class="ui-widget-overlay ui-front"></div>
<div id="message-text" class="ui-dialog ui-widget ui-widget-content ui-corner-all ui-front ui-draggable ui-resizable waitmessage">please wait...</div>
</div>
现在你应该实现任何元素来下载:
<a class="download" href="file://www.ocelot.com.pl/prepare-report">Download report</a>
or
<input class="download" type="submit" value="Download" name="actionType">
每次点击下载后,您将看到消息:
您的报告正在创建中。请稍等…
我也遇到过同样的问题。我的解决方案是使用临时文件,因为我已经生成了一堆临时文件。提交表格时:
var microBox = {
show : function(content) {
$(document.body).append('<div id="microBox_overlay"></div><div id="microBox_window"><div id="microBox_frame"><div id="microBox">' +
content + '</div></div></div>');
return $('#microBox_overlay');
},
close : function() {
$('#microBox_overlay').remove();
$('#microBox_window').remove();
}
};
$.fn.bgForm = function(content, callback) {
// Create an iframe as target of form submit
var id = 'bgForm' + (new Date().getTime());
var $iframe = $('<iframe id="' + id + '" name="' + id + '" style="display: none;" src="about:blank"></iframe>')
.appendTo(document.body);
var $form = this;
// Submittal to an iframe target prevents page refresh
$form.attr('target', id);
// The first load event is called when about:blank is loaded
$iframe.one('load', function() {
// Attach listener to load events that occur after successful form submittal
$iframe.load(function() {
microBox.close();
if (typeof(callback) == 'function') {
var iframe = $iframe[0];
var doc = iframe.contentWindow.document;
var data = doc.body.innerHTML;
callback(data);
}
});
});
this.submit(function() {
microBox.show(content);
});
return this;
};
$('#myForm').bgForm('Please wait...');
在生成文件的脚本的末尾:
header('Refresh: 0;url=fetch.php?token=' . $token);
echo '<html></html>';
这将导致iframe上的load事件被触发。然后关闭等待消息,然后开始文件下载。它在Internet Explorer 7和Firefox上进行了测试。
基于Elmer的例子,我准备了自己的解决方案。单击具有定义的“download”类的项目后,浏览器窗口中将显示一条自定义消息。我用焦点触发器隐藏了消息。我用焦点触发器隐藏了消息。
JavaScript
$(function(){$('.download').click(function() { ShowDownloadMessage(); }); })
function ShowDownloadMessage()
{
$('#message-text').text('Your report is creating. Please wait...');
$('#message').show();
window.addEventListener('focus', HideDownloadMessage, false);
}
function HideDownloadMessage(){
window.removeEventListener('focus', HideDownloadMessage, false);
$('#message').hide();
}
HTML
<div id="message" style="display: none">
<div id="message-screen-mask" class="ui-widget-overlay ui-front"></div>
<div id="message-text" class="ui-dialog ui-widget ui-widget-content ui-corner-all ui-front ui-draggable ui-resizable waitmessage">please wait...</div>
</div>
现在你应该实现任何元素来下载:
<a class="download" href="file://www.ocelot.com.pl/prepare-report">Download report</a>
or
<input class="download" type="submit" value="Download" name="actionType">
每次点击下载后,您将看到消息:
您的报告正在创建中。请稍等…
我在这个配置中遇到了同样的问题:
Struts 1.2.9
jQuery 1.3.2。
jQuery UI 1.7.1.custom
Internet Explorer 11
Java 5
我用饼干的解决方案:
客户端:
在提交表单时,调用JavaScript函数隐藏页面并加载等待的旋转器
function loadWaitingSpinner() {
... hide your page and show your spinner ...
}
然后,调用一个函数,每500毫秒检查一次cookie是否来自服务器。
function checkCookie() {
var verif = setInterval(isWaitingCookie, 500, verif);
}
如果找到cookie,停止每500毫秒检查一次,使cookie过期并调用函数返回页面并删除等待spinner (removeWaitingSpinner())。如果您希望能够再次下载另一个文件,过期cookie是很重要的!
function isWaitingCookie(verif) {
var loadState = getCookie("waitingCookie");
if (loadState == "done") {
clearInterval(verif);
document.cookie = "attenteCookie=done; expires=Tue, 31 Dec 1985 21:00:00 UTC;";
removeWaitingSpinner();
}
}
function getCookie(cookieName) {
var name = cookieName + "=";
var cookies = document.cookie
var cs = cookies.split(';');
for (var i = 0; i < cs.length; i++) {
var c = cs[i];
while(c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
function removeWaitingSpinner() {
... come back to your page and remove your spinner ...
}
服务器端:
在服务器进程结束时,向响应添加一个cookie。当您的文件准备好下载时,cookie将被发送到客户端。
Cookie waitCookie = new Cookie("waitingCookie", "done");
response.addCookie(waitCookie);