jQuery.when().done() 不工作

jQuery .when().done() not working

首先我想说我是 jQuery 的新手,我怀疑我只是在做一些愚蠢的事情,所以希望这对某些人来说非常简单。

我正在尝试向我的网站添加滑动移动子菜单。我想要一种手风琴效果,如果我单击一个父项 link,它的子菜单将打开,所有其他子菜单将关闭。问题是时间 - 子菜单打开,然后通过重置所有子菜单再次关闭。我认为答案是使用 deferreds 但我尝试过的一切都失败了。这是(目前不工作)代码:

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;
});

如有任何帮助,我们将不胜感激。谢谢!

罗内尔

这是使用 jQuery.when() 的常见错误。

jQuery.when() 需要承诺作为参数。它没有神奇的力量来知道你传递给它的功能何时以某种方式完成。这些函数必须 return 承诺在底层代码完成后得到解决或拒绝,然后您可以将这些承诺传递给 jQuery.when()

您的 ResetMenu() 函数没有 return 任何东西,因此,您的 jQuery.when() 不会等待任何东西。它立即执行 .then() 处理程序(这看起来不是你想要的)。

因此,在这一行中:

jQuery.when(ResetMenu()).done(OpenSubmenu());

ResetMenu() 必须 return 承诺 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() 的方式,这既使它只是一个可以稍后执行的函数引用,又绑定了适当的 this 值对它:

jQuery.when(ResetMenu()).done(OpenSubmenu.bind(this));

请注意,.bind(this) 假定 this 是合适的值。您可以在那里传递任何值是正确的值,并且在执行时将成为 OpenSubmenu() 内部的 this 值。

当您将非承诺对象传递给 $.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;
});