이벤트 버블 링 및 캡처 란 무엇입니까?


답변:


1439

이벤트 버블 링 및 캡처는 다른 요소 내부의 요소에서 이벤트가 발생하고 두 요소가 해당 이벤트에 대한 핸들을 등록한 경우 HTML DOM API에서 이벤트 전파의 두 가지 방법입니다. 이벤트 전파 모드 는 요소가 이벤트를 수신하는 순서를 결정 합니다 .

버블 링을 통해 이벤트는 먼저 가장 안쪽 요소에 의해 캡처되고 처리 된 다음 외부 요소로 전파됩니다.

캡처하면 이벤트가 가장 바깥 쪽 요소에 의해 먼저 캡처되어 안쪽 요소로 전파됩니다.

캡처는 "트릭 링"이라고도하며 전파 순서를 기억하는 데 도움이됩니다.

물방울, 거품

예전에는 Netscape가 이벤트 캡처를 옹호했고 Microsoft는 이벤트 버블 링을 홍보했습니다. 둘 다 W3C Document Object Model Events 표준 (2000)의 일부입니다.

IE <9는 이벤트 버블 링 만 사용 하지만 IE9 + 및 모든 주요 브라우저는 둘 다를 지원합니다. 반면 에 복잡한 DOM 의 경우 이벤트 버블 링 성능이 약간 떨어질 수 있습니다 .

addEventListener(type, listener, useCapture)버블 링 (기본값) 또는 캡처 모드에서 이벤트 핸들러를 등록 하는 데 사용할 수 있습니다 . 캡처 모델을 사용하려면으로 세 번째 인수를 전달하십시오 true.

<div>
    <ul>
        <li></li>
    </ul>
</div>

위의 구조에서 li요소 에서 클릭 이벤트가 발생했다고 가정하십시오 .

캡처 모델에서 이벤트는 div첫 번째 ( divwill 에서 click 이벤트 핸들러가 먼저 실행 됨)에 의해 처리 된 다음 ul대상 요소에서 마지막으로 처리됩니다 li.

버블 링 모델에서는 반대 현상이 발생합니다. 이벤트는 먼저 li, 그 다음으로 ul, 마지막으로 div요소가 처리합니다.

자세한 내용은

아래 예에서 강조 표시된 요소를 클릭하면 이벤트 전파 흐름의 캡처 단계가 먼저 발생하고 버블 링 단계가 발생 함을 알 수 있습니다.

var logElement = document.getElementById('log');

function log(msg) {
    logElement.innerHTML += ('<p>' + msg + '</p>');
}

function capture() {
    log('capture: ' + this.firstChild.nodeValue.trim());
}

function bubble() {
    log('bubble: ' + this.firstChild.nodeValue.trim());
}

function clearOutput() {
    logElement.innerHTML = "";
}

var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
    divs[i].addEventListener('click', capture, true);
    divs[i].addEventListener('click', bubble, false);
}
var clearButton = document.getElementById('clear');
clearButton.addEventListener('click', clearOutput);
p {
    line-height: 0;
}

div {
    display:inline-block;
    padding: 5px;

    background: #fff;
    border: 1px solid #aaa;
    cursor: pointer;
}

div:hover {
    border: 1px solid #faa;
    background: #fdd;
}
<div>1
    <div>2
        <div>3
            <div>4
                <div>5</div>
            </div>
        </div>
    </div>
</div>
<button id="clear">clear output</button>
<section id="log"></section>

JSFiddle의 또 다른 예 .


41
useCapture현재 IE> = 9에서 지원됩니다. source
beatgammit

7
댓글을 작성하기에는 너무 늦었지만 여기에서 찾은 훌륭한 기사 catcode.com/domcontent/events/capture.html
그냥 코드

3
triclkling은 동일 capturing? 대한 크록 포드 회담 Trickling v. Bubbling이 비디오 이야기에서 - youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB의 주변 1 hr 5 minutes.
케빈 메러디스

1
@KevinMeredith 같은 것. "살수은"그냥 쉽게 두 모델은 (세류 않는 것을 기억하게 아래로 , 거품 까지 ).
고양이

7
위의 대답은 자세한 설명의 순서와 관련하여 정확하지만 "버블 업, 물방울 다운"으로 세류가 두 번째로 발생한다고 생각하게합니다. 이벤트는 항상 버블 단계 전에 캡처 단계를 거칩니다. 올바른 순서는 trickle down=> onElement=>bubble up
14

513

기술:

quirksmode.org 에 이에 대한 멋진 설명이 있습니다. 간단히 말해서 (quirksmode에서 복사) :

이벤트 캡처

이벤트 캡처를 사용하는 경우

               | |
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  \ /          |     |
|   -------------------------     |
|        Event CAPTURING          |
-----------------------------------

element1의 이벤트 핸들러가 먼저 실행되고 element2의 이벤트 핸들러가 마지막으로 실행됩니다.

이벤트 버블 링

이벤트 버블 링을 사용하는 경우

               / \
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  | |          |     |
|   -------------------------     |
|        Event BUBBLING           |
-----------------------------------

element2의 이벤트 핸들러가 먼저 실행되고 element1의 이벤트 핸들러가 마지막으로 실행됩니다.


무엇을 사용해야합니까?

그것은 당신이하고 싶은 것에 달려 있습니다. 더 나은 없습니다. 차이점은 이벤트 핸들러 실행 순서입니다. 대부분의 경우 버블 링 단계 에서 이벤트 핸들러를 시작하는 것이 좋지만 더 일찍 실행해야 할 수도 있습니다.


먼저 캡처 한 다음 버블 링이 발생하지 않으며 디스패치 이벤트가 무엇입니까?
Suraj Jain

그래픽 예제는 다음과 같습니다. javascript.info/bubbling-and-capturing
커뮤니티 Ans

71

요소 1과 요소 2가 2 개있는 경우 요소 2는 요소 1 안에 있고 두 요소가 모두 포함 된 이벤트 핸들러를 연결하면 onClick이라고 말할 수 있습니다. 이제 요소 2를 클릭하면 두 요소 모두에 대한 eventHandler가 실행됩니다. 이제 질문은 이벤트가 실행될 순서입니다. 요소 1에 첨부 된 이벤트가 먼저 실행되면 이벤트 캡처라고하고 요소 2에 첨부 된 이벤트가 먼저 실행되면이를 이벤트 버블 링이라고합니다. W3C에 따라 이벤트는 대상에 도달 할 때까지 캡처 단계에서 시작하여 요소로 돌아와 버블 링을 시작합니다.

캡처 및 버블 링 상태는 addEventListener 메소드의 useCapture 매개 변수로 알려져 있습니다.

eventTarget.addEventListener (type, listener, [, useCapture]);

기본적으로 useCapture는 false입니다. 그것은 버블 링 단계에 있다는 것을 의미합니다.

var div1 = document.querySelector("#div1");
var div2 = document.querySelector("#div2");

div1.addEventListener("click", function (event) {
  alert("you clicked on div 1");
}, true);

div2.addEventListener("click", function (event) {
  alert("you clicked on div 2");
}, false);
#div1{
  background-color:red;
  padding: 24px;
}

#div2{
  background-color:green;
}
<div id="div1">
  div 1
  <div id="div2">
    div 2
  </div>
</div>

참과 거짓을 바꾸어보십시오.


2
@masterxilo : Fiddle이 필요 없으며, 이제 StackOverflow는 인라인 코드 (스택 스 니펫)를 지원합니다 .
Dan Dascalescu

에 관해서 the event will start in the capturing phase untill it reaches the target comes back to the element and then it starts bubbling. addEventListener 에는 useCapturetrue 또는 false로 설정할 수있는 매개 변수 만 있습니다. 및 HTML 4.0, 이벤트 리스너는 요소의 속성으로 지정된useCapture defaults to false. 작성한 내용을 확인하는 사양에 연결할 수 있습니까?
surfmuggle

25

이 주제를 설명하는 데 javascript.info 에서이 학습서 가 매우 명확 하다는 것을 알았습니다 . 그리고 마지막 3 점 요약은 실제로 중요한 점에 대해 이야기하고 있습니다. 나는 여기에 인용한다.

  1. 이벤트는 먼저 가장 깊은 대상으로 캡처 된 다음 버블 업됩니다. IE <9에서는 거품 만 발생합니다.
  2. 모든 처리기 addEventListener는 마지막 인수를 제외 하고 버블 링 단계에서 작동하며 true, 캡처 단계에서 이벤트를 포착하는 유일한 방법입니다.
  3. 버블 링 / 캡쳐는 event.cancelBubble=true(IE) 또는 event.stopPropagation() 다른 브라우저에 의해 중지 될 수 있습니다 .

7

Event.eventPhase이벤트가 대상에 있는지 또는 다른 곳에서 왔는지 알려줄 수 있는 속성 도 있습니다.

브라우저 호환성은 아직 결정되지 않았습니다. Chrome (66.0.3359.181) 및 Firefox (59.0.3)에서 테스트했으며 지원됩니다.

허용 된 답변에서 이미 훌륭한 스 니펫을 확장 하면 eventPhase속성을 사용하여 출력됩니다.

var logElement = document.getElementById('log');

function log(msg) {
  if (logElement.innerHTML == "<p>No logs</p>")
    logElement.innerHTML = "";
  logElement.innerHTML += ('<p>' + msg + '</p>');
}

function humanizeEvent(eventPhase){
  switch(eventPhase){
    case 1: //Event.CAPTURING_PHASE
      return "Event is being propagated through the target's ancestor objects";
    case 2: //Event.AT_TARGET
      return "The event has arrived at the event's target";
    case 3: //Event.BUBBLING_PHASE
      return "The event is propagating back up through the target's ancestors in reverse order";
  }
}
function capture(e) {
  log('capture: ' + this.firstChild.nodeValue.trim() + "; " + 
  humanizeEvent(e.eventPhase));
}

function bubble(e) {
  log('bubble: ' + this.firstChild.nodeValue.trim() + "; " + 
  humanizeEvent(e.eventPhase));
}

var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
  divs[i].addEventListener('click', capture, true);
  divs[i].addEventListener('click', bubble, false);
}
p {
  line-height: 0;
}

div {
  display:inline-block;
  padding: 5px;

  background: #fff;
  border: 1px solid #aaa;
  cursor: pointer;
}

div:hover {
  border: 1px solid #faa;
  background: #fdd;
}
<div>1
  <div>2
    <div>3
      <div>4
        <div>5</div>
      </div>
    </div>
  </div>
</div>
<button onclick="document.getElementById('log').innerHTML = '<p>No logs</p>';">Clear logs</button>
<section id="log"></section>


5

버블 링

  Event propagate to the upto root element is **BUBBLING**.

캡처

  Event propagate from body(root) element to eventTriggered Element is **CAPTURING**.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.