子と親の両方がクリック可能です(子はjQueryクリックイベントを持つリンクまたはdivである可能性があります)。子をクリックすると、親クリックイベントのみをトリガーし、子イベントはトリガーしません。
イベントには3つのフェーズがあります。
<window>
で始まり、子孫を通じてイベントのターゲットに向かって呼び出される「キャプチャ」です。また、イベントには「デフォルトアクション」があり、これはバブリングフェーズの後に発生します。デフォルトのアクションは、通常、イベントのターゲットである要素の種類の指定されたタイプのイベントに対して発生するブラウザ定義のアクションです(たとえば、href
で<a>
のclick
にナビゲートし、別のイベントでclick
要素のタイプには異なるデフォルトアクションがあります)。
DOM Level 3 Events draft には、イベントがDOMを介して伝播する方法をグラフィカルに示す図があります。
Image Copyright©2016 World Wide Web Consortium 、( [〜#〜] mit [〜#〜] 、 [〜# 〜] ercim [〜#〜] 、 Keio 、 Beihang )。 http://www.w3.org/Consortium/Legal/2015/doc-license ( ライセンスごとに許可された使用 )
キャプチャとバブリングの詳細については、「 イベントのバブリングとキャプチャとは何ですか? 」を参照してください。 DOM Level 3 Events draft ;または W3C DOM4:Events
必要に応じて、子のイベントの前に親でイベントを取得し、防止するには、キャプチャフェーズでイベントを受信する必要があります。キャプチャフェーズでそれを受け取ったら、DOMツリーの下位の要素のイベントハンドラー、またはバブリングフェーズでリッスンするように登録されているイベントハンドラー(つまり、要素/フェーズのすべてのリスナー)にイベントが伝播するのを停止する必要がありますリスナーの後にイベントが訪れます)。これを行うには、 event.stopPropagation()
を呼び出します。
addEventListener(type, listener[, useCapture])
でリスナーを追加する場合、useCapture
引数をtrue
にすることができます。
MDNの引用:
[
useCapture
is]このタイプのイベントは、DOMツリーでその下のEventTargetにディスパッチされる前に、登録されたリスナーにディスパッチされることを示すブール値 。ツリーを上方向にバブリングしているイベントは、キャプチャを使用するように指定されたリスナーをトリガーしません。イベントのバブリングとキャプチャは、両方の要素がそのイベントのハンドルを登録したときに、別の要素内にネストされた要素で発生するイベントを伝播する2つの方法です。イベント伝播モードは、要素がイベントを受け取る順序を決定します。詳細な説明については、DOMレベル3イベントおよびJavaScriptイベントの順序を参照してください。指定しない場合、useCapture
はデフォルトでfalseになります。
event.preventDefault()
は、デフォルトのアクションを防止するために使用されます(たとえば、href
でブラウザが<a>
のclick
にナビゲートするのを防ぎます)。 [これは以下の例で使用されていますが、テキストに対するデフォルトのアクションがないため、実際の効果はありません。ここでは、ほとんどの場合、クリックイベントハンドラーを追加するときにデフォルトのアクションを回避するために使用されます。したがって、そうする習慣を身に付けることは良い考えであり、あなたがしたくないことがわかっているときはそうしないことです。event.stopPropagation()
は、イベントフェーズのいずれかで後の要素のハンドラーがイベントを受け取らないようにするために使用されます。追加のハンドラー現在の要素とフェーズでが呼び出されることを妨げません。デフォルトのアクションが発生するのを防ぎません。event.stopImmediatePropagation()
:同じ要素とフェーズのハンドラーは、追加された順に呼び出されます。 event.stopPropagation()
と同じ効果を持つことに加えて、event.stopImmediatePropagation()
は、追加のハンドラー同じ要素およびイベントフェーズがイベントを受信することを防ぎます。デフォルトのアクションが発生するのを防ぎません。この質問の要件は、イベントが子に伝播するのを防ぐことであるため、これを使用する必要はありませんが、event.stopPropagation()
を使用する代わりに使用できます。ただし、同じ要素のリスナーは追加された順に呼び出されることに注意してください。したがって、event.stopImmediatePropagation()
は、リスナーの前に追加されたリスナーと同じ要素およびフェーズのリスナーによるイベントの受信を妨げません。次の例では、イベントリスナーは親と子の両方の<div>
要素に配置されます。子より前のキャプチャフェーズでイベントを受信し、event.stopPropagation()
を実行するため、親に配置されたリスナーのみがイベントを受信します。
var parent=document.getElementById('parent');
var child=document.getElementById('child');
var preventChild=document.getElementById('preventChild');
parent.addEventListener('click',function(event){
if(preventChild.checked) {
event.stopPropagation();
}
event.preventDefault();
var targetText;
if(event.target === parent) {
targetText='parent';
}
if(event.target === child) {
targetText='child';
}
console.log('Click Detected in parent on ' + targetText);
},true);
child.addEventListener('click',function(event){
console.log('Click Detected in child (bubbling phase)');
});
child.addEventListener('click',function(event){
console.log('Click Detected in child (capture phase)');
},true);
<input id="preventChild" type="checkbox" checked>Prevent child from getting event</input>
<div id="parent">Parent Text<br/>
<div id="child" style="margin-left:10px;">Child Text<br/>
</div>
</div>
jQueryは、イベントでのキャプチャの使用をサポートしていません。理由の詳細については、「 jQueryイベントモデルがイベントキャプチャをサポートせず、イベントバブリングをサポートする理由 」を参照してください。
子要素のいずれもインタラクティブではないことがわかっている特定の状況で役立つ可能性のあるこの別のオプションは、CSSでpointer-events: none
を設定することです( link )。通常、インタラクションをキャプチャする要素のすべての子要素に適用します。このような:
#parentDiv * {
pointer-events: none
}
*
に注意して、ルールがparentDiv
のすべての子に適用されることを宣言します。