web-dev-qa-db-ja.com

JavaScriptで複数のaddEventListenerはどのように機能しますか?

ドキュメントには2つのスクリプトがあります

// my_script.js goes first
document.onclick = function() {
    alert("document clicked");
};

// other_script.js comes after
// this overrides the onclick of my script,
// and alert will NOT be fired
document.onclick = function() {
    return false;
};

クリックイベントが他のスクリプトによって上書きされないようにするために、addEventListenerに切り替えました。

// my_script.js goes first
document.addEventListener("click", function() {
    alert("document clicked");
}, false);

// other_script.js comes after
document.addEventListener("click", function() {
    return false;
}, false);

今、私は別の質問を受けました。 2番目のコードのreturn falsealertの後に定義されているのに、なぜアラートの呼び出しを妨げないのでしょうか。

スクリプトでクリックイベントを完全に制御したい場合はどうなりますか(他のスクリプトで定義されているイベントを無視して常にfalseを返すなど)?

13
user1643156

スクリプトでクリックイベントを完全に制御したい場合はどうなりますか(他のスクリプトで定義されているイベントを無視して常にfalseを返すなど)?

ハンドラーを最初に登録できる場合は、登録する前に、使用しているブラウザーがDOM3イベントを正しく実装していれば(IE8以前でない限り、おそらく登録します)、登録できます。

ここには(少なくとも)4つのことが関係しています:

  1. デフォルトを防ぐ。

  2. 祖先要素への伝播を停止します。

  3. same要素の他のハンドラーが呼び出されないようにします。

  4. ハンドラーが呼び出される順序。

順番に:

1.デフォルトの防止

これは、DOM0ハンドラーのreturn falseが行うことです。 (詳細: False を返すストーリー。)DOM2とDOM3で同等のものは preventDefault

document.addEventListener("click", function(e) {
    e.preventDefault();
}, false);

デフォルトを防ぐことは、あなたがしていることにそれほど関係がないかもしれませんが、DOM0ハンドラーでreturn falseを使用していて、それがデフォルトを防ぐので、完全を期すためにここに含めます。

2.祖先要素への伝播を停止します

DOM0ハンドラーにはこれを行う方法がありません。 DOM2のものは、 stopPropagation を介して行います:

document.addEventListener("click", function(e) {
    e.stopPropagation();
}, false);

ただし、stopPropagationは、同じ要素の他のハンドラーが呼び出されるのを停止しません。から 仕様

stopPropagationメソッドが使用され、イベントフロー中にイベントがさらに伝播するのを防ぎます。このメソッドがEventListenerによって呼び出された場合、イベントはツリー内での伝播を停止します。 イベントは、イベントフローが停止する前に、現在のEventTarget上のすべてのリスナーへのディスパッチを完了します。

(私の強調。)

3。same要素の他のハンドラーが呼び出されないようにする

当然、これはDOM0では発生しませんでした。これは、同じ要素で同じイベントに対して他のハンドラーがbeできないためです。 :-)

私の知る限り、DOM2でこれを行う方法はありませんが、DOM3では stopImmediatePropagation

document.addEventListener("click", function(e) {
    e.stopImmediatePropagation();
}, false);

一部のライブラリは、ライブラリを介して接続されたハンドラーに対してこの機能を提供します(IE8などの非DOM3システムでも)。以下を参照してください。

4.ハンドラーが呼び出される順序

繰り返しますが、他のハンドラーは存在し得ないため、DOM0に関連するものではありません。

DOM2では、仕様explicitlyは、要素にアタッチされたハンドラーが呼び出される順序が保証されていないことを示しています。しかし、DOM3はそれを変更し、ハンドラーは登録された順序で呼び出されると言っています。

まず、DOM2から セクション1.2.1

EventListeners上のすべてのEventTargetは、そのEventTargetによって受信されたイベントによってトリガーされることが保証されていますが、受信する順序については指定されていません。 EventListeners上の他のEventTargetに関するイベント。

しかし、これはDOM3に取って代わられます セクション3.1

次に、実装は現在のターゲットの候補イベントリスナーを決定する必要があります。これは、現在のターゲットに登録されているすべてのイベントリスナーのリストである必要があります。

(私の強調。)

一部のライブラリは、イベントをライブラリに接続することを条件に、順序を保証します。

また、MicrosoftのDOM2の前身(例:attachEvent)では、DOM3の順序とは逆でした。ハンドラーはの登録順序で呼び出されていました。 。


したがって、#3と#4を一緒にすると、ハンドラーを最初に登録できる場合は、ハンドラーが最初に呼び出され、stopImmediatePropagationを使用して他のハンドラーが呼び出されないようにすることができます。ブラウザがDOM3を正しく実装している場合。


これらすべて(IE8以前はDOM2イベントを実装しておらず、DOM3も実装していないという事実を含む)は、jQueryのようなライブラリを使用する理由の1つであり、その一部は順序を保証します(すべてがを介してハンドラーを接続している限り)問題のライブラリ)、同じ要素上の他のハンドラーでさえも呼び出されないようにする方法を提供します。 (たとえば、jQueryの場合、順序はアタッチされた順序であり、stopImmediatePropagationを使用して他のハンドラーへの呼び出しを停止できます。ただし、ここではjQueryを販売しようとはしておらず、 libsは、基本的なDOMのものよりも多くの機能を提供します。)

49
T.J. Crowder