web-dev-qa-db-ja.com

子がクリックされたときに親クリックイベントのみをトリガーする方法

子と親の両方がクリック可能です(子はjQueryクリックイベントを持つリンクまたはdivである可能性があります)。子をクリックすると、親クリックイベントのみをトリガーし、子イベントはトリガーしません。

21
Mike Li

DOMイベントフェーズ

イベントには3つのフェーズがあります。

  1. Capture:最初のフェーズは、イベントハンドラが<window>で始まり、子孫を通じてイベントのターゲットに向かって呼び出される「キャプチャ」です。
  2. Target:2番目のフェーズは、ターゲットのイベントリスナーが呼び出される「ターゲット」フェーズです。
  3. バブリング:3番目のフェーズは「バブリング」で、最初に呼び出されるターゲットの親をリッスンするハンドラーから開始され、次にその先祖が徐々に呼び出されます素子。

また、イベントには「デフォルトアクション」があり、これはバブリングフェーズの後に発生します。デフォルトのアクションは、通常、イベントのターゲットである要素の種類の指定されたタイプのイベントに対して発生するブラウザ定義のアクションです(たとえば、href<a>clickにナビゲートし、別のイベントでclick要素のタイプには異なるデフォルトアクションがあります)。

DOM Level 3 Events draft には、イベントがDOMを介して伝播する方法をグラフィカルに示す図があります。

Graphical representation of an event dispatched in a DOM tree using the DOM event flow
Image Copyright©2016 World Wide Web Consortium 、( [〜#〜] mit [〜#〜][〜# 〜] ercim [〜#〜]KeioBeihang )。 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は、イベントでのキャプチャの使用をサポートしていません。理由の詳細については、「 jQueryイベントモデルがイベントキャプチャをサポートせず、イベントバブリングをサポートする理由 」を参照してください。

71
Makyen

子要素のいずれもインタラクティブではないことがわかっている特定の状況で役立つ可能性のあるこの別のオプションは、CSSでpointer-events: noneを設定することです( link )。通常、インタラクションをキャプチャする要素のすべての子要素に適用します。このような:

#parentDiv * {
    pointer-events: none
}

*に注意して、ルールがparentDivのすべての子に適用されることを宣言します。

15
Abraham Brookes