javascript事件の泡が現れて、詳しい解と捕獲、阻止方法


一、事件の発生順序
この問題の起源は非常に簡単で、もしあなたがもう一つの要素の中に他の要素を入れ込んでいると仮定します。

-----------------------------------
| element1                        |
|   -------------------------     |
|   |element2               |     |
|   -------------------------     |
|                                 |
-----------------------------------
:両方ともオンClickイベント処理関数があります。ユーザーが要素2をクリックすると、要素1と要素2のクリックイベントがトリガされます。しかし、どのイベントが先にトリガされますか?どのイベント処理関数が先に実行されますか?つまり、事件の発生順はどうなりますか?
二種類のモデル
案の定、「振り返るに忍びない」(ブラウザ大戦)の日には、Netscapeとマイクロソフトの2つの異なる処理方法があります。
Netscapeは、要素1のイベントが最初に発生すると主張しています。このようなイベントの発生順序はキャプチャ型と呼ばれています。
マイクロソフトは元素2を保持して優先権を持っています。このような事件の順序は発泡型と呼ばれています。
この二つの事件の順序ははっきりと反対である。Explorerブラウザは、発泡事象のみをサポートしています。Mozila、Opera 7、Konquerer両方ともサポートしています。もっと古いoperaとiCabは両方とも支持していません。
三、捕獲型イベント
捕獲型イベントを使用すると

               | |
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  \ /          |     |
|   -------------------------     |
|        Event CAPTURING          |
-----------------------------------
:要素1のイベントハンドラ関数が最初にトリガされ、要素2のイベントハンドラ関数が最後にトリガされます。
四、バブル型事件
バブル型のイベントを使う時

               / \
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  | |          |     |
|   -------------------------     |
|        Event BUBBLING           |
-----------------------------------
:要素2の処理関数は、まずトリガされ、要素1の次に
五、W 3 Cモデル
W 3 cは賢明にもこの争いの中で選択された方案です。w 3 cイベントモデルで発生したイベントのうち、最初はターゲット要素に到達するまで捕獲段階に進み、更に発泡段階に入る。

                 | |  / \
-----------------| |--| |-----------------
| element1       | |  | |                |
|   -------------| |--| |-----------     |
|   |element2    \ /  | |          |     |
|   --------------------------------     |
|        W3C event model                 |
------------------------------------------
ウェブ開発者のために、捕獲段階であるかそれとも発泡段階であるかを選択することができます。これはaddEventListener()法によって実現されます。この関数の最後のパラメータがtrueであれば、捕獲段階でのバインディング関数、逆false、発泡段階でのバインディング関数です。
あなたが作るなら

element1.addEventListener('click',doSomething2,true)

element2.addEventListener('click',doSomething,false)

ユーザーが要素2をクリックすると、次のようになります。
(事件はここでは観光客のように、外から内へ観光して、触発された主要な要素に近づいてきて、また逆に離れていく)
1.イベントをクリックし、まずキャプチャ段階に入ります。要素2の祖先元素の中に、捕獲段階においてonclick処理関数があるかどうかを確認します。
2.元素1が一つあることが分かりました。ドソmething 2が実行されます。
3.イベントはターゲット自身(要素2)をチェックしましたが、捕獲段階ではより多くの処理関数が発見されませんでした。イベントは発泡段階に入り始め、当然ながらドソメット()を実行したいと思います。これは元素2の発泡段階の関数に結び付けられています。
4.イベントは要素2から離れる方向に向かって、どのような祖先元素が発泡段階で一つの処理関数に結びつけられているかを確認します。このような状況がないので、何も起こりませんでした。
反対の場合は、

element1.addEventListener('click',doSomething2,false)

element2.addEventListener('click',doSomething,false)

今ユーザーが要素2をクリックすると発生します。
1.イベントをクリックしてキャプチャフェーズに入ります。元素2の祖先元素の中に、捕獲段階においてonclick処理関数があるかどうかを確認したが、結果は何も得られなかった。
2.事件は目標自分をチェックする。イベントは発泡段階に入り始め,要素2の発泡相に結合された関数を実行した。ドソメイシング()
3.イベントは目標から離れ始め、要素2の祖先元素の中に処理関数が発泡段階で結合されているかどうかを確認する。
4.一つが見つかったので、要素1のドソメンテーション2()が実行されます。
六、互換性と伝統モデル
w 3 c dom(ドキュメントオブジェクトモデル)をサポートするブラウザで、従来のイベントバインディング方法は
element1.onclick = doSomething2;
デフォルトは、発泡段階にバインディングされていると見なされます。
七、泡を使った事件
まれな開発者は、バブル型のイベントや捕獲型のイベントを意識的に使う。彼らが今日作ったウェブページの中で、一つの事件を泡のためにいくつかの関数で処理する必要がない。しかし、ユーザーは通常、彼らがマウスを1回クリックしただけで、多くの場合(複数の関数が実行され、泡が発生するため)が発生してしまうので、疑問に思うことがあります。多くの場合、あなたはやはりあなたの処理関数が独立してほしいです。ユーザーがある元素をクリックしたら、何が起きますか?他の元素をクリックして、何が発生しますか?
八、ずっと起きています。
まず第一に、事件の捕獲や泡が発生していることを理解してください。ページ全体の定義を与えると、汎用的なOclick処理関数があります。

document.onclick = doSomething;
if (document.captureEvents) document.captureEvents(Event.CLICK);
ページ上で任意の要素のクリックイベントをクリックすると、最終的にページの一番上の文書層に泡ができます。したがって、その汎用的な処理関数をトリガします。前の処理関数で明確に指摘されていない限り、発泡はドキュメント全体に広がりません。
上のコードに対して第二文の補足:
>>先にIEを話します
object.set Capture()は、一つのobjectがsetCaptureされると、彼の方法はドキュメント全体に引き継がれてキャプチャされます。
ドキュメント全体に方法を引き継ぐ必要がない場合は、object.release Capture()を使用します。
>>>others
Mozillaにも似たような機能があります。方法はちょっと違います。
window.cpatureEvents(Event.eventType)
window.release Event(EventType)
>>example
//         ,     obj     click    obj.onclick = function(){alert("something")}
// , document( window, )
obj.captureEvents(Event.click); //FF
obj.setCapture()  //IE
九、使い方
どのイベントの伝播もページドキュメント(この最上位層)で終了しますので、デフォルトのイベントハンドラが可能になります。このようなページがあると仮定してください。

------------------------------------
| document                         |
|   ---------------  ------------  |
|   | element1    |  | element2 |  |
|   ---------------  ------------  |
|                                  |
------------------------------------
element1.onclick = doSomething;
element2.onclick = doSomething;
document.onclick = defaultFunction;
 
現在、ユーザーが要素1または要素2をクリックすると、ドソmething()が実行されます。もしあなたが望むなら、イベントをdefaultFunctionに泡を作りたくないなら、ここでイベントの泡が上に広がるのを止めることができます。しかし、ユーザーがページ上の他の部分をクリックすると、defaultFunction()が実行されます。このような効果は時には使えるかもしれません。
ページの設定­――処理関数を広範囲のトリガ面積にするには、「ドラッグ効果」スクリプトで必要です。一般的には、ある要素層でmousedownイベントが起こるということは、この要素が選択され、mousemooveイベントに応答できるようにすることを意味する。mousedownは通常、ブラウザのbugを回避するためにこの要素層に結びつけられているが、他の2つのイベント関数の範囲はページ全体でなければならない(?)
ブラウザ学の第一法則(First Law of Browserology)を覚えてください。すべてが可能です。そして、少なくとも準備ができている時です。そのため、ユーザーがドラッグした時、大幅にページ上で彼のマウスを移動しましたが、スクリプトは大幅に反応できず、マウスも元素層に留まらなくなりました。
1.onmouseover処理関数が元素層に結合されている場合、この元素層はマウスの移動に対して何の反応もしないので、ユーザーに違和感を与えます。
2.onmouseup処理関数が要素層に結合されている場合、イベントもトリガされず、結果として、ユーザーがこの元素層を下に置いた後、元素層はマウス移動に反応し続けます。これはより多くの迷いを引き起こす(?)
したがって、この例では、イベントの泡が非常に効果的です。あなたの処理関数をページ層に置いて、彼らが常に実行されることを保証できます。
十、それを止めました。
しかし、一般的には、関数間の邪魔にならないように、すべての泡を切って捕獲したいと思います。これ以外にも、かなり複雑な構造の文書(多くのテーブル同士が入れ子になっているか、あるいはこれらのような)があれば、システムリソースを節約するために、泡が出てきます。この時、ブラウザはターゲット要素の各祖先を確認し、処理関数があるかどうかを確認しなければなりません。一つも見つからなかったとしても、先ほどの検索には時間がかかります。
マイクロソフトのモデルでは、イベントのcancel Bubble属性をtrueに設定しなければなりません。
window.event.cancelBubble = true
w 3 cモデルではイベントのstopPropagationを呼び出す必要があります。
e.stopPropagation()
これはすべての泡が外に広がるのを阻止します。ブラウザをまたぐソリューションとしては、このようにすべきです。

function doSomething(e)

{
      if (!e) var e = window.event;

         e.cancelBubble = true;

         if (e.stopPropagation) e.stopPropagation();

}

cancel Bubble属性をサポートするブラウザにcancel Bubbleを設置するのは大層な問題がありません。ブラウザは肩をすくめてこの属性を作成します。もちろんこれは本格的に泡をキャンセルすることはできませんが、少なくともこのコマンドは安全で正しいです。
十一、currentTarget
私たちが前に見たように、一つのイベントはtargetまたはsrcellement属性を用いて、イベントがどのターゲット要素(即ちユーザが最初にクリックした要素)にあるかを表します。私たちの例では元素2です。クリックしたからです。
非常に重要なことは、捕獲または発泡段階におけるターゲット要素は不変であり、常に要素2に関連していることを理解することである。
以下の関数を紐付けたと仮定します。
element1.onclick = doSomething;

element2.onclick = doSomething;

ユーザーが要素2をクリックすると、doSomething()が2回実行されます。しかし、どのhtml元素がこの事件に応答しているかどうやって分かりますか?target/srcellementも手がかりを与えていませんが、人々はいつも要素2に傾いています。これはイベントを引き起こす原因です。
この問題を解決するために、w 3 cはcurrentTargetという属性を増加させ、イベントを処理している要素を指す。残念ながら、マイクロソフトのモデルには似たような属性がありません。
あなたも「this」というキーワードを使ってもいいです。上記の例では、事件を処理しているhtml要素に相当し、まるでcurrentTargetのようです。
十二、マイクロソフトモデルの問題
しかし、マイクロソフトのイベントバインディングモデルを使用すると、thisのキーワードはHTMLの要素に相当しません。連想にはcurrentTargetのようなマイクロソフトモデルが欠けています。上のコードによって操作すれば、あなたがそうするという意味です。
element1.attachEvent('onclick',doSomething)

element2.attachEvent('onclick',doSomething)

どのHTML元素が事件を処理しているかを正確に知ることができません。これはマイクロソフトのイベントバインディングモデルの一番深刻な問題です。私にとって、これもWindowsの下でIEだけのアプリケーションを開発しているからです。
できるだけ早くcurrentTargetの似たような属性を増加したいです。あるいは標準に従いますか?ウェブ開発者にはこれらの情報が必要です。
後記:
javascriptを実戦で経験したことがないので、この文章の一部のところはあまり理解できません。無理に翻訳するしかないです。例えば、ドラッグ効果の話をしています。
 PS:JSイベントに関するオンライン検索ツールを紹介します。JSでよく使われるイベントの種類と関数機能をまとめました。
javascriptイベントと機能説明大全:
http://tools.jb51.net/table/javascript_イベント