addEventListener에서 useCapture 매개 변수를 이해할 수 없습니다.


290

https://developer.mozilla.org/en/DOM/element.addEventListener 에서 기사를 읽었 지만 useCapture속성 을 이해할 수 없습니다 . 정의는 다음과 같습니다.

true 인 경우, useCapture는 사용자가 캡처를 시작하려고 함을 나타냅니다. 캡처를 시작하면 지정된 유형의 모든 이벤트가 등록 된 리스너로 전달되고 DOM 트리에서 그 아래의 EventTarget으로 전달됩니다. 트리를 통해 위로 버블 링하는 이벤트는 캡처를 사용하도록 지정된 리스너를 트리거하지 않습니다.

이 코드에서 부모 이벤트는 자식보다 먼저 트리거되므로 해당 동작을 이해할 수 없습니다.

function load() {
  document.addEventListener("click", function() {
    alert("parent event");
  }, true);

  document.getElementById("div1").addEventListener("click", function() {
    alert("child event");
  }, false);
}
<body onload="load()">
  <div id="div1">click me</div>
</body>

답변:


350

이벤트는 시작 ( "캡처")과 끝 ( "버블")의 두 경우에 활성화 될 수 있습니다. 이벤트는 정의 된 순서대로 실행됩니다. 다음과 같이 4 개의 이벤트 리스너를 정의하십시오.

window.addEventListener("click", function(){console.log(1)}, false);
window.addEventListener("click", function(){console.log(2)}, true);
window.addEventListener("click", function(){console.log(3)}, false);
window.addEventListener("click", function(){console.log(4)}, true);

로그 메시지는 다음 순서로 나타납니다.

  • 2(먼저 정의 capture=true)
  • 4(을 사용하여 두 번째로 정의 됨 capture=true)
  • 1(와 함께 처음 정의 된 이벤트 capture=false)
  • 3(와 함께 정의 된 두 번째 이벤트 capture=false)

49
실행의 주문이됩니다 보장 할 수 없습니다 : no specification is made as to the order in which they will receive the event with regards to the other EventListeners on the EventTarget. 모든 브라우저를 테스트하지는 않았으므로 동일한 방식으로 구현할 수 있습니다. 그러나 캡처 이벤트는 캡처하지 않는 이벤트보다 먼저 수행됩니다.
beatgammit

47
실행 순서가 @tjameson 되는 DOM2 사양의 후속 보장, DOM3 이벤트 : "구현은 현재 대상의 결정해야 후보의 이벤트 리스너를 이에 현재 대상에 등록 된 모든 이벤트 리스너의 목록이어야합니다 그. 등록 순서. "
Rob W

1
이것은 기본적으로 이벤트 주문 할 수있어되도록 같아요
slier

1
@slier, yes, 동일한 이벤트에 대한 여러 핸들러가 실행되는 순서.
JMD

6
인접 이벤트 처리기의 실행 순서를 지시하는 것이 아니라 전파 동작에 대한 이야기를 캡처하고 버블 링하기 때문에 afaik, 왜 받아 들여지는 대답
인지 모르겠습니다.

272

이 다이어그램은 캡처 / 대상 / 버블 단계를 이해하는 데 매우 유용합니다. http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

아래는 링크에서 컨텐츠를 추출한 것입니다.

단계

이벤트는 트리의 루트에서이 대상 노드까지의 경로를 따라 전달됩니다. 그런 다음 대상 노드 수준에서 로컬로 또는 트리에서 상위의 대상 조상에서 처리 할 수 ​​있습니다. 이벤트 전달 (이벤트 전파라고도 함)은 3 단계와 다음 순서로 발생합니다.

  1. 캡처 단계 : 이벤트는 트리의 루트에서 대상 노드의 직접 상위로 대상의 조상에 전달됩니다.
  2. 대상 단계 : 이벤트가 대상 노드로 전달됩니다.
  3. 버블 링 단계 : 이벤트가 대상 노드의 직접 상위에서 트리의 루트로 대상의 상위 항목으로 전달됩니다.

DOM 이벤트 흐름을 사용하여 DOM 트리에 전달 된 이벤트의 그래픽 표현

대상의 조상은 이벤트가 처음 전달되기 전에 결정됩니다. 디스패치 중에 대상 노드가 제거되거나 대상의 조상이 추가 또는 제거되면, 이벤트 전파는 항상 대상 노드와 디스패치 전에 결정된 대상의 조상을 기반으로합니다.

일부 이벤트는 DOM 이벤트 흐름의 3 단계를 반드시 수행 할 필요는 없습니다. 예를 들어, 이벤트는 1 단계 또는 2 단계에 대해서만 정의 될 수 있습니다. 예를 들어,이 사양에 정의 된 이벤트는 항상 캡처 및 대상 단계를 수행하지만 일부는 버블 링 단계를 수행하지 않습니다 ( "버블 링 이벤트"대 "비 버블 링 이벤트", Event.bubbles 속성 참조).


1
아주 좋은 다이어그램!
Alex

1
대상 노드의 자식은 어떻습니까? 그들은 언제 이벤트를 받습니까?
Aurimas

자식 이기 때문에 실제로 트리의 루트가 Window아닌 입니까? documentdocumentWindow
stackjlei

1
@Aurimas 그들은 이해가되지 않습니다. 대상은 이벤트를 수신해야하는 가장 안쪽 요소입니다. <body> 요소 (빈 곳)를 클릭하면 <body> 내부의 모든 요소 (= 페이지의 모든 요소)가 클릭 이벤트를받지 않아야합니다.
amik

1
"무엇"에 "왜"가 포함되어 있는지 설명하는 모든 자료를 원합니다. 평소처럼 더 많은 인터넷 검색을 사용하지 않습니다.
aaaaaa

80

캡처 이벤트 ( useCapture = true) vs 버블 이벤트 ( useCapture = false)

MDN 참조

  • 캡처 이벤트는 버블 이벤트 전에 발송됩니다
  • 이벤트 전파 순서는
    1. 부모 캡처
    2. 어린이 캡처
    3. 대상 캡처 및 대상 버블
      • 그들이 등록 된 순서대로
      • 요소가 이벤트의 대상인 경우 useCapture매개 변수는 중요하지 않습니다 (감사합니다 @bam 및 @ legend80s).
    4. 어린이 버블
    5. 부모 버블
  • stopPropagation() 흐름을 막을 것이다

캡처 흐름 사용

데모

결과:

  1. 부모 캡처
  2. 대상 버블 1

    (Capture 및 Bubble of Target이 등록 된 순서대로 트리거되므로 Bubble 이벤트는 Capture 이벤트 전에 트리거됩니다)

  3. 대상 캡처

  4. 대상 버블 2
  5. 부모 버블

var parent = document.getElementById('parent'),
target = document.getElementById('target');

target.addEventListener('click', function (e) { 
console.log('Target Bubble 1');
// e.stopPropagation();
}, false);

target.addEventListener('click', function (e) { 
console.log('Target Capture');
// e.stopPropagation();
}, true);

target.addEventListener('click', function (e) { 
console.log('Target Bubble 2');
// e.stopPropagation();
}, false);

parent.addEventListener('click', function (e) { 
console.log('Parent Capture');
// e.stopPropagation();
}, true);

parent.addEventListener('click', function (e) { 
console.log('Parent Bubble');
// e.stopPropagation();
}, false);
<div id="parent">
    <button id="target" style="padding: 1em 0.8em;">
        Trigger event
    </button>
</div>


1
예를 들어 실수가 있습니다. 다음과 같은 순서로 자식 이벤트를 선언했습니다. 1. 자식 캡처 2. 자식 거품 중요합니다! Child가 이벤트의 대상이 될 경우에도 동일한 순서로 리스너가 호출됩니다. 요소가 이벤트 'useCapture'매개 변수의 대상인 경우 MDN의 참고 사항을 참조하십시오. ( developer.mozilla.org/en-US/docs/Web/API/EventTarget/… )
bam

1
참고 : 이벤트 대상에 연결된 이벤트 리스너의 경우 이벤트는 캡처 및 버블 링 단계가 아닌 대상 단계에 있습니다. Events in the target phase will trigger all listeners on an element in the order they were registered, regardless of the useCapture parameter.에서 developer.mozilla.org/en-US/docs/Web/API/EventTarget/... . 따라서 "Children Capture"및 "Children Bubble"단계는 없습니다.
legend80s

그리고 다이어그램에서 어떤 요소에 대해 "캡처"가 항상 먼저 발생해야한다고 제안 할 때 예제를 실행하면 "어린이 캡처"전에 "어린이 버블 1"이 생성되는 이유를 설명합니다!
Gershom

18

useCapture = true라고 말하면 이벤트가 캡처 단계에서 위에서 아래로 실행됩니다. false이면 아래에서 위로 버블을 수행합니다.


11

이벤트 모델에 관한 모든 것 : http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow 버블 링 단계 또는 캡처 단계에서 이벤트를 잡을 수 있습니다. 당신의 선택. http://www.quirksmode.org/js/events_order.html을
살펴보십시오 . 매우 유용합니다.


1
w3에 대한 링크는 Google 검색보다 유용하거나 그다지 유용하지 않습니다.
Muhammad Umer

3
예, w3 링크는 방대한 단어이지만 그 반대의 경우 quirksmode 사이트에 대한 두 번째 링크 는 주제를 매우 간단하고 간단하게 설명합니다.
Stano

11

코드 예 :

<div id="div1" style="background:#9595FF">
  Outer Div<br />
  <div id="div2" style="background:#FFFFFF">
    Inner Div
  </div>
</div>

자바 스크립트 코드 :

d1 = document.getElementById("div1");
d2 = document.getElementById("div2");

둘 다 false로 설정된 경우

d1.addEventListener('click',function(){alert("Div 1")},false);
d2.addEventListener('click',function(){alert("Div 2")},false);

실행 : Inner Div를 클릭하면 경고가 Div 2> Div 1로 표시됩니다.

여기서 스크립트는 내부 요소에서 실행됩니다. 이벤트 버블 링 (useCapture가 false로 설정 됨)

div 1이 true로 설정되고 div 2가 false로 설정되었습니다.

d1.addEventListener('click',function(){alert("Div 1")},true);
d2.addEventListener('click',function(){alert("Div 2")},false);

실행 : Inner Div를 클릭하면 경고가 Div 1> Div 2로 표시됩니다.

여기서 스크립트는 조상 / 외부 요소에서 실행됩니다. 이벤트 캡처 (useCapture가 true로 설정 됨)

div 1은 false로 설정되고 div 2는 true로 설정됩니다.

d1.addEventListener('click',function(){alert("Div 1")},false);
d2.addEventListener('click',function(){alert("Div 2")},true);

실행 : Inner Div를 클릭하면 경고가 Div 2> Div 1로 표시됩니다.

여기서 스크립트는 내부 요소에서 실행됩니다. 이벤트 버블 링 (useCapture가 false로 설정 됨)

div 1이 true로 설정되고 div 2가 true로 설정되었습니다.

d1.addEventListener('click',function(){alert("Div 1")},true);
d2.addEventListener('click',function(){alert("Div 2")},true);

실행 : Inner Div를 클릭하면 경고가 Div 1> Div 2로 표시됩니다.

여기서 스크립트는 조상 / 외부 요소에서 실행됩니다. useCapture가 true로 설정된 이후의 이벤트 캡처


1
이 맥락에서 "보다 큰"갈매기 형의 의미는 무엇입니까?
2540625

9

요약:

DOM사양에 설명 :

https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

다음과 같은 방식으로 작동합니다.

이벤트는 document트리 의 루트 ( )에서 대상 노드 까지의 경로를 따라 전달 됩니다. 대상 노드는 가장 깊은 HTML요소입니다 (예 : event.target). 이벤트 전달 (이벤트 전파라고도 함)은 3 단계와 다음 순서로 발생합니다.

  1. 캡처 단계 : 이벤트는 트리의 루트 ( document)에서 대상 노드의 직접 상위로 대상의 상위 항목으로 전달됩니다.
  2. 대상 단계 : 이벤트가 대상 노드로 전달됩니다. 목표 단계는 항상 html이벤트가 분리 된 가장 깊은 요소에 있습니다.
  3. 버블 링 단계 : 이벤트가 대상 노드의 직접 상위에서 트리의 루트로 대상의 상위 항목으로 전달됩니다.

이벤트 버블 링, 이벤트 캡처, 이벤트 대상

예:

// bubbling handlers, third argument (useCapture) false (default)
document.getElementById('outerBubble').addEventListener('click', () => {
  console.log('outerBubble');
}, false)

document.getElementById('innerBubble').addEventListener('click', () => {
  console.log('innerBubble');
}, false)


// capturing handlers, third argument (useCapture)  true
document.getElementById('outerCapture').addEventListener('click', () => {
  console.log('outerCapture');
}, true)

document.getElementById('innerCapture').addEventListener('click', () => {
  console.log('innerCapture');
}, true)
div:hover{
  color: red;
  cursor: pointer;
}
<!-- event bubbling -->
<div id="outerBubble">
  <div id="innerBubble">click me to see Bubbling</div>
</div>


<!-- event capturing -->
<div id="outerCapture">
  <div id="innerCapture">click me to see Capturing</div>
</div>

위의 예는 실제로 이벤트 버블 링과 이벤트 캡처의 차이점을 보여줍니다. 로 이벤트 리스너를 추가 할 때 addEventListeneruseCapture라는 세 번째 요소가 있습니다. 이것은 이벤트 리스너가 이벤트 버블 링 대신 이벤트 캡처를 사용할 수 있도록 boolean설정된 경우입니다 true.

예제에서 useCapture 인수를 설정하면 false이벤트 버블 링이 발생 함을 알 수 있습니다. 먼저 대상 단계에서 이벤트가 시작되고 (innerBubble 로그) 이벤트 버블 링을 통해 상위 요소의 이벤트가 시작됩니다 (outerBubble 로그).

useCapture 인수를 설정하면 true외부의 이벤트 <div>가 먼저 시작됩니다. 이벤트가 버블 링 단계가 아니라 캡처 단계에서 시작 되었기 때문입니다.


7

이벤트 여행 의 3 단계를 고려하면 다음과 같습니다.

  1. 캡처 단계는 : 이벤트는 대상 노드의 직접 부모 트리의 루트에서 대상의 조상에 전달됩니다.
  2. 대상 단계는 : 이벤트는 대상 노드에 전달됩니다.
  3. 버블 링 단계는 : 이벤트가 트리의 루트 대상 노드의 직접적인 부모 대상의 조상에 전달됩니다.

useCapture이벤트 여행 이 진행되는 단계를 나타냅니다 .

인 경우 true, useCapture 는 사용자가 캡처 단계에 대해서만 이벤트 리스너를 추가하려고 함을 나타냅니다. 즉,이 이벤트 리스너는 대상 및 버블 링 단계 중에 트리거되지 않습니다. 인 경우 false대상 및 버블 링 단계 중에 만 이벤트 리스너가 트리거됩니다.

출처는 두 번째 최상의 답변과 동일합니다 : https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases


2

정의 순서는 항목이 동일한 수준에있는 경우에만 중요합니다. 코드에서 정의 순서를 반대로 바꾸면 동일한 결과를 얻을 수 있습니다.

그러나 두 이벤트 핸들러에서 useCapture 설정을 되 돌리면 하위 이벤트 핸들러가 상위 이벤트 핸들러보다 먼저 응답합니다. 그 이유는 상위 이벤트 핸들러가 트리거되는 버블 링 단계 이전의 캡처 단계에서 하위 이벤트 핸들러가 트리거되기 때문입니다.

정의 순서에 관계없이 두 이벤트 핸들러 모두에 대해 useCapture를 true로 설정하면 상위 이벤트 핸들러가 캡처 단계에서 하위 이벤트보다 먼저 발생하므로 상위 이벤트 핸들러가 먼저 트리거됩니다.

반대로, 정의 순서에 관계없이 두 이벤트 핸들러 모두에 대해 useCapture를 false로 설정하면 버블 링 단계에서 상위 이벤트 이벤트보다 먼저 하위 이벤트 핸들러가 시작되므로 하위 이벤트 핸들러가 먼저 트리거됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.