Как правильно упорядочить события анимации с помощью процедур в JQuery
У меня было немного трудное время, пытаясь упорядочить некоторые анимационные события в JQuery с рядом других процедур, которые я пытаюсь выполнить одновременно или в определенной последовательности. Вот в основном то, что я хочу достичь:
- Пользователь нажимает на кнопку, которая вызывает всплывающее окно настраиваемого div на экране.
- Всплывающее окно анимируется вместе с фоном.
- Во всплывающем окне отображается сообщение о загрузке, в то время как оно также отправляет (после 1,5-секундной задержки) запрос Ajax на сервер, чтобы извлечь указанное содержимое, которое затем будет загружено во всплывающее окно.
- Затем всплывающее окно загрузки текста должно быть заменено полученным содержимым через боковую сторону.
- Когда пользователь читает сообщение, он / она может щелкнуть значок закрытия всплывающего окна или нажать клавишу выхода, чтобы закрыть всплывающее окно.
- Всплывающее окно закрывается с помощью анимации затухания.
С моим текущим кодом (ссылка ниже на JSFiddle), это, кажется, работает нормально, и анимация всплывающего окна и последовательность будут отображаться правильно, при условии, что пользователь сначала закрывает всплывающее окно, прежде чем нажать на кнопку, чтобы показать его снова. ОДНАКО (и это моя проблема)... если всплывающее окно остается открытым, и пользователь снова нажимает кнопку, последовательность анимации нарушается... кажется, что цепочка событий разваливается - процедура, которая показывает, что всплывающее окно не ждет его закрытия, и вы получаете ужасный эффект.
Любые идеи о том, как это может быть решено?
В идеале, как подсказывает логика в коде, мы бы хотели дождаться полной анимации закрытия всплывающего окна, прежде чем снова запустить анимацию показа всплывающего окна. Я все еще немного новичок, когда дело доходит до JQuery, так что прости меня. Я попытался провести некоторое исследование и считаю, что решение может заключаться в использовании Deferreds каким-то умным способом. Тем не менее, я подумал, что вы, ребята, можете предложить отличное, эффективное и современное решение и помешать мне вырвать все мои волосы. знак равно
Вот мой код (местами несколько упрощенный, но все еще хорошо имитирующий проблему):
1 ответ
Мне удалось решить мою проблему и правильно настроить последовательность всех событий. Потребовалось некоторое умное использование Отложенных и много проб и ошибок, прежде чем я понял, что я на самом деле делаю. В любом случае, если кому-то нужно это решение для всего, над чем он работает...
Эта проблема:
Я хотел, чтобы на моей странице появилось всплывающее окно с сообщениями, чтобы по существу заменить окно предупреждений браузера для моих целей. Я хотел создать цепочку анимации исчезновения и скольжения, чтобы показать окно сообщения, а затем его содержимое. Я также хотел, чтобы загрузочное изображение появлялось в окне сообщения при его первом появлении, в то время как асинхронный запрос отправлялся на сервер. В окне сообщения будет показан ответ. Во всяком случае, так я это настроил...
В теле моего 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();
});
}
};
Как вы можете видеть, в нескольких точках последовательности скрытия / показа я использую отложенные элементы, чтобы разрешить выполнение определенных событий перед запуском новых. Для справки, это мои привязки:
// 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.');
}
});
});