我设法解决了我的问题并让我的所有事件都正确排序。在我掌握我实际在做的事情之前,我巧妙地使用了 Deferreds 并进行了大量的试验和错误。无论如何,如果有人需要这个解决方案来解决他们正在做的任何事情......
问题:
我希望在我的页面上弹出一个消息框,以从本质上替换浏览器的警报窗口以达到我的目的。我想链接一些淡入淡出和滑动动画来显示消息框,然后显示它的内容。我还希望加载图像在第一次出现时出现在消息框中,同时向服务器发送异步请求。消息框将显示响应。反正我是这样设置的...
在我的 html 正文中,我包含了消息框容器:
<div id="msg-box">
<div id="msg-box-container">
<div id="msg-box-headbar">
<div id="msg-box-title"></div>
<div id="msg-box-clButton"></div>
</div>
<div id="msg-box-content"></div>
<div id="msg-box-footbar"></div>
</div>
</div>
<div id="msg-box-backdrop"></div>
如您所见,我的消息框还有一个背景(我将其设置为位于消息框容器之外的半透明 div)。背景将同时显示和动画,但独立于消息框本身。这是另一个复杂因素,因为事件的顺序和时间必须正确执行,否则我们会得到奇怪的效果……比如背景在做一件事,而消息框在做另一件事。
脚本:
为了使我的代码更简洁,在我的第一次尝试中,我为消息框创建了一个对象字面量,其中包含一组用于操作消息框的函数。这需要大量研究,但最终的解决方案是使用链式和延迟的组合。最后,我的代码如下所示:
var msgBox = {
status: 0,
self: $('#msg-box'),
title: $('#msg-box-title'),
cl_button: $('#msg-box-clButton'),
content: $('#msg-box-content'),
backdrop: $('#msg-box-backdrop'),
hideBox: function() {
var b = this;
if (b.status == 1) {
var dfd = $.Deferred();
b.self.fadeOut(500);
b.backdrop.fadeOut(500, dfd.resolve);
b.status = 0;
return dfd.promise();
}
},
showBox: function(ttl, msg) {
var b = this;
if (b.status == 1) {
$.when(b.hideBox()).then(function() {
b.doShow();
b.loadCont(ttl, msg);
});
}
else {
if(b.backdrop.queue().length > 0) {
$.when(b.backdrop.queue()).done( function() {
b.doShow();
b.loadCont(ttl, msg);
});
}
else {
b.doShow();
b.loadCont(ttl, msg);
}
}
},
doShow: function() {
var b = this;
b.title.text('Loading...');
b.content.html('<div id="msg-box-loader"><img id="loading-img" src="/graphics/loader-16.gif" /></div>');
b.backdrop.height(b.self.height());
b.self.centerBox($(window).width());
b.backdrop.centerBox($(window).width());
b.self.fadeIn('fast');
b.backdrop.corner('round 6px').fadeTo('fast', 0.6);
},
loadCont: function(ttl, msg) {
var b = this;
b.content.delay(1500).queue(function(next) {
b.title.text(ttl);
b.content.text(msg).slideDown('fast');
b.backdrop.height(b.self.height()).slideDown('fast');
b.status = 1;
next();
});
}
};
如您所见,在隐藏/显示序列中的几个点,我使用 Deferreds 来允许某些事件在启动新事件之前完成。作为参考,这些是我的绑定:
// events related to message box
$(document).keydown( function(e) {
if (e.keyCode == 27) {
e.preventDefault();
if(msgBox.status == 1)
msgBox.hideBox();
}
});
msgBox.cl_button.hover( function() { $(this).toggleClass('no-hover').toggleClass('hover'); });
msgBox.self.on('click', msgBox.cl_button.selector, function() { msgBox.hideBox(); });
$(window).resize(function() {
if (msgBox.status == 1) {
msgBox.self.centerBox($(window).width());
msgBox.backdrop.centerBox($(window).width());
}
});
// login form submitted
$('#login-form').submit( function(e) {
e.preventDefault();
var postData = 'async=login&user='+$('#login-user').val()+'&pass='+hex_md5($('#login-pass').val());
$.ajax({ type: 'POST', url: "index.php", data: postData,
success: function(response) {
if(response==0) msgBox.showBox('Login Failed', 'Invalid Credentials');
else if(response==1) msgBox.showBox('Success', response);
else msgBox.showBox('Internal Error', 'There was an internal error. Please contact the administrator.<br><br>'+response);
},
error: function() {
msgBox.showBox('Internal Error', 'There was an internal error. Please contact the administrator.');
}
});
});