web-dev-qa-db-ja.com

jQuery .when()。done()が機能しない

私がjQueryを初めて使用することから始めて、私は愚かなことをしているだけだと思う​​ので、誰かにとってこれが非常に簡単であることを願っています。

スライド式のモバイルサブメニューをウェブサイトに追加しようとしています。 1つの親リンクをクリックすると、子のサブメニューが開き、他のすべてのサブメニューが閉じるというアコーディオン効果が必要です。問題はタイミングです-子サブメニューが開き、すべてのサブメニューをリセットすることで再び閉じます。答えは遅延オブジェクトを使用することだと思いますが、私が試したすべてが失敗しています。これは(現在は機能していない)コードです:

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

どんな助けでも大歓迎です。ありがとうございました!

ロネル

13
Ronelz

これは、jQuery.when()の使用方法でよくある間違いです。

jQuery.when()には、引数としてpromiseが必要です。渡した関数がいつか完了したことを知る魔法の力はありません。これらの関数は、基になるコードが完了したときに解決または拒否されたプロミスを返さなければならず、それらのプロミスをjQuery.when()に渡すことができます。

ResetMenu()関数は何も返さないため、jQuery.when()は何も待機しません。これは.then()ハンドラーをすぐに実行します(これは必要な処理ではないようです)。

したがって、この行では:

_jQuery.when(ResetMenu()).done(OpenSubmenu());
_

ResetMenu()は、jQuery.when()がいつ完了したかを知るためのpromiseを返す必要があります。

これを行うことで、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値になります。

25
jfriend00

$.when()に非promiseオブジェクトを渡すと、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;
});
3
Arun P Johny