32

私は既存のWebアプリで作業しています。アプリには、さまざまなフォームにさまざまな送信ボタンがあり、通常のhttp投稿を使用するもの、onClick関数を定義するもの、クラスを使用してjsイベントハンドラーをボタンにバインドするものがありますエレメント。

私がしたいのは、ボタンにクラスを追加するだけで別のイベントハンドラーをこれらのボタンにバインドすることですが、私が決定したいのは、新しいイベントハンドラーが実行されることが保証されるか、またはフォーム送信アクションの1つが発生するかですそれが私の新しい機能がヒットしないことを意味する前に。

シナリオの例は、これらのボタンにクラスを追加して、すべてのボタンを共通の js 関数にバインドし、単に使用状況をいくつかの API に記録することです。フォームの送信がページから移動したためにログ機能が呼び出されないリスクはありますか?

私は大量の js 開発を行ったことがありません。これを 100 回以上テストして、運良く起動できました。


以下は、例の 1 つでテストしたコードです。繰り返しますが、複数のイベントをバインドする方法を尋ねているわけではありません。問題は、仕様の理解と、すべてのハンドラーの実行が保証されているかどうかです。

$(document).ready(function(){
    $('.testingBtn').click(function() {
        window.location.replace("http://stackoverflow.com");
    });
    $( ".testingBtn" ).click(function(){
        alert('submitting!');
    });
});


<input class="testingBtn" type="submit" id="submitform" value="Complete Signup" />

上記のように、複数のイベントをバインドすることができます。この例では、別の URL に誘導するだけですが、これはform.submit().

4

3 に答える 3

63

JS では、イベント ハンドラーが呼び出される順序を実際に制御することはできませんが、慎重に委譲し、適切に配置されたリスナーを使用すれば可能です。

委任は、イベント モデルの最も強力な機能の 1 つです。ご存じかもしれませんが、ご存知かもしれませんが、JS では、イベントは dom の一番上に渡され、そこからイベントが適用される要素に伝播されます。したがって、グローバル オブジェクトにアタッチされたイベント リスナーが、要素自体にアタッチされたリスナーより前にそのハンドラーを呼び出すのは当然のことです。

window.addEventListener('click',function(e)
{
    e = e || window.event;
    var target = e.target || e.srcElement;
    console.log('window noticed you clicked something');
    console.log(target);//<-- this is the element that was clicked
}, false);//<-- we'll get to the false in a minute

ハンドラ内のイベント オブジェクトに実際にアクセスできることに注意してください。この場合、イベント オブジェクトをそのままにしておいたので、ターゲットまで伝播し続けます。その途中で、次のようなものに遭遇する可能性があります。

document.getElementById('container').addEventListener('click', function(e)
{
    e = e || window.event;
    var target = e.target || e.srcElement;
    if (target.tagName.toLowerCase() !== 'a' || target.className.match(/\bclickable\b/))
    {
        return e;//<return the event, unharmed
    }
    e.returnValue = false;
    if (e.preventDefault)
    {
        e.preventDefault();
    }
}, false);

現在、このハンドラーは、ウィンドウ レベルのリスナーがそのヘルパーを呼び出した後に呼び出されます。今回は、クリックされた要素にクラスがない場合、または要素がリンクの場合、イベント変更されます。clickableイベントはキャンセルされますが、まだ生きています。イベントは dom のさらに下に自由に伝播できるため、次のようなことが発生する可能性があります。

document.getElmentById('form3').addEventListener('click',function(e)
{
     e = e || window.event;
     if (e.returnValue === false || e.isDefaultPrevented)
     {//this event has been changed already
         //do stuff, like validation or something, then you could:
         e.cancelBubble = true;
         if (e.stopPropagation)
         {
             e.stopPropagation();
         }
     }
}, false);

ここでは、 を呼び出すことstopPropagationで、イベントが強制終了されます。イベントがすでに変更されていない限り、dom のさらに下のターゲットに伝播することはできません。そうでない場合、イベント オブジェクトは、何も起こらなかったかのように、DOM をさらに下に移動します。

ターゲット ノードに到達すると、イベントは 2 番目のフェーズであるバブル フェーズに入ります。DOM の奥深くまで伝播するのではなく、トップ レベルに戻ります (ディスパッチされたグローバル オブジェクトまで、どこから来たのかなど)。

バブル段階では、伝播段階と同じルールがすべて適用されますが、その逆のみです。イベント オブジェクトは、最初にターゲット要素に最も近い要素に遭遇し、最後にグローバル オブジェクトに遭遇します。

ここには、これに関する便利で明確な図がたくさんあります。私はそれを良い 'ol quirksmode よりもうまく表現することはできません.

結論: 2 つのイベント リスナーを扱う場合は、両方を異なるレベルにアタッチして、好きなようにキューに入れます。

両方が呼び出されることを保証したい場合は、最後に呼び出されるハンドラーでのみイベントの伝播を停止します。

同じイベントの同じ要素/オブジェクトにアタッチされた 2 つのリスナーがある場合、最初にアタッチされたリスナーが最初に呼び出されなかったという状況に遭遇したことはありません。

それだけです、私は理にかなっていることを願って、ベッドに向かいます

于 2013-06-27T20:51:27.923 に答える
13

jQuery はこれを簡単にします。

$(document).on('click', '.someclass', function() {
  doStuff();
});

$(document).on('click', '.someclass', function() {
  doMoreStuff();
});

ハンドラーは、両方ともクリックで起動します。jQuery は、ハンドラーのキューを保持します。また、選択したセレクターに一致するドキュメントのクリックを処理して、ボタンがいつ作成されてもトリガーできるようにします。

于 2013-06-27T20:06:16.753 に答える