JQuery.when(). done() не работает
Я хотел бы начать с того, что я новичок в jQuery, и я подозреваю, что я просто делаю что-то глупое, так что, надеюсь, это будет очень просто для кого-то.
Я пытаюсь добавить скользящее мобильное подменю на свой сайт. Я хочу гармонический эффект, при котором, если я нажму одну родительскую ссылку, откроется дочернее подменю и все остальные подменю будут закрыты. Проблема заключается в синхронизации - дочернее подменю открывается, а затем снова закрывается сбросом всех подменю. Я предполагаю, что ответ заключается в использовании отложенных дней, но все, что я пробовал, потерпело неудачу. Это код (в настоящее время не работает):
function ResetMenu(){
jQuery(".mobile-menu").find(".sub-menu").slideUp(100);
jQuery(".mobile-menu").find(".menu-item-has-child").removeClass("open");
};
function OpenSubmenu(){
jQuery(this).next("ul").slideDown(100);
jQuery(this).parent().addClass("open");
};
jQuery("li.menu-item-has-children > a").click(function(){
if(jQuery(this).parent().hasClass("open")){
jQuery(".mobile-menu").find(".sub-menu").slideUp(100);
jQuery(this).parent().removeClass("open");
} else {
jQuery.when(ResetMenu()).done(OpenSubmenu());
}
return false;
});
Любая помощь будет принята с благодарностью. Спасибо!
Ronel
Ответы
Ответ 1
Это распространенная ошибка в использовании jQuery.when()
.
jQuery.when()
требует promises в качестве аргументов. У него нет магических способностей знать, когда функции, которые вы передаете, как-то сделаны. Эти функции ДОЛЖНЫ возвращать promises, которые разрешаются или отклоняются при выполнении базового кода, и затем вы можете передать эти promises в jQuery.when()
.
Ваша функция ResetMenu()
ничего не возвращает, поэтому ваш jQuery.when()
не ждет ничего. Он немедленно выполняет обработчик .then()
(что выглядит не так, как вы хотите).
Итак, в этой строке:
jQuery.when(ResetMenu()).done(OpenSubmenu());
ResetMenu()
ДОЛЖЕН вернуть обещание jQuery.when()
знать, когда это будет сделано.
Вы можете исправить ResetMenu()
для работы таким образом:
function ResetMenu(){
return jQuery(".mobile-menu").find(".sub-menu").slideUp(100).promise().then(function() {
// remove this class when the animation has completed
jQuery(".mobile-menu").find(".menu-item-has-child").removeClass("open");
});
};
И, кроме того, вам нужно изменить способ передачи функции на .done()
на это, что делает это просто ссылкой на функцию, которая может быть выполнена LATER и привязывает к ней соответствующее значение this
:
jQuery.when(ResetMenu()).done(OpenSubmenu.bind(this));
Примечание. .bind(this)
предполагает, что this
является подходящим значением. Вы можете передать любое значение, соответствующее этому значению, и оно станет значением this
внутри OpenSubmenu()
при его выполнении.
Ответ 2
Когда вы передаете объект без обещаний $.when()
, вызывающие вызовы, переданные в done()
, вызываются немедленно, в вашем случае, когда ResetMenu
не возвращает ничего, вызываемое OpenSubmenu
, есть и другая проблема - вам не следует ссылаться непосредственно на OpenSubmenu
(добавив ()
), вам нужно передать ссылку на функцию done()
function ResetMenu() {
jQuery(".mobile-menu").find(".menu-item-has-child").removeClass("open");
return jQuery(".mobile-menu").find(".sub-menu").slideUp(100).promise();
};
function OpenSubmenu() {
jQuery(this).next("ul").slideDown(100);
jQuery(this).parent().addClass("open");
};
jQuery("li.menu-item-has-children > a").click(function () {
if (jQuery(this).parent().hasClass("open")) {
jQuery(".mobile-menu").find(".sub-menu").slideUp(100);
jQuery(this).parent().removeClass("open");
} else {
jQuery.when(ResetMenu()).done(OpenSubmenu);
}
return false;
});