JavaScript

버블링(bubbling) vs 캡처링(capturing)

짱닭 2020. 10. 16. 15:33
반응형

eventListener() vs onclick()를 이해하기 위해 간단히 개념만 설명했다.
자세한 설명은 하단 출처 참고.

버블링

한 요소에 이벤트가 발생하면, 이 요소에 할당된 핸들러가 동작하고, 이어서 부모 요소의 핸들러가 동작한다.
가장 최상단의 조상 요소를 만날 때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작한다.

3개의 요소 ( form > div > p )가 있다
form 안에 div 안에 p요소가 있는 형태.

각 요소를 클릭하면 alert()가 호출된다.

직접 확인 : plnkr.co/plunk/FDfhm3tzwTz3B6Fb

가장 안쪽의 p요소를 클릭하면 다음과 같은 실행과정이 발생한다.

  1. 에 할당된onclick핸들러가 동작.

  2. 바깥의
    에 할당된 핸들러가 동작.
  3. 그 바깥의
    에 할당된 핸들러가 동작.
  4. document객체(최상위 객체)를 만날 때까지, 각 요소에 할당된onclick핸들러가 동작.

위와 같은 순서로 실행 되므로 가장 안쪽의 p요소를 클릭하면
p→div→form순서로 3개의 alert() 경고창이 뜨게 된다.

이런 흐름을 '이벤트 버블링’이라고 부른다.
이벤트가 제일 깊은 곳에 있는 요소에서 시작해 부모 요소를 거슬러 올라가며 발생하는 모양이
마치 물속 거품(bubble)과 닮았기 때문.

"모든" 이벤트에 적용되는 특징이 아니다

event.target

부모 요소의 핸들러는 이벤트가 정확히 어디서 발생했는지 등에 대한 정보를 얻을 수 있다.

이벤트가 발생한 가장 안쪽의 요소는 타겟(target) 요소라고 불리고,
event.target 을 사용해 접근 가능.

event.target과 this(event.currentTarget)의 차이

- event.target 은 실제 이벤트가 시작된 '타겟' 요소이다. 버블링이 진행되어도 변하지 않음.
- this 는 '현재' 요소로, 현재 실행중인 핸들러가 할당된 요소. 버블링 진행시 변화.

다시 form안에 div 안에 p 요소가 중첩되어있다고 하자.

이벤트 핸들러는 form.onclick 하나뿐이라고 할 때,
이 핸들러는 form 안의 모든 요소에서 발생하는 클릭 이벤트를 잡아(catch)낸다.

클릭 이벤트가 어디서 발생되었든지 상관없이 form 요소까지 이벤트가 버블ㄹ이되어 핸들러를 실행시키기 때문.

직접 확인 :ko.javascript.info/article/bubbling-and-capturing/bubble-target/

script.js 내용

form.onclick = function(event) {
  event.target.style.backgroundColor = 'yellow';

  // chrome needs some time to paint yellow
  setTimeout(() => {
    alert("target = " + event.target.tagName + ", this=" + this.tagName);
    event.target.style.backgroundColor = ''
  }, 0);
};

버블링 중단하기는 출처 참고.

캡쳐링

이벤트엔 버블링 이외에도 ‘캡처링(capturing)’ 이라는 흐름이 존재합니다.
실제 코드에서 자주 쓰이진 않지만, 종종 유용한 경우가 있음.

표준DOM 이벤트에서 정의한 이벤트 흐름의 3가지 단계

  1. 캡처링 단계 – 이벤트가 하위 요소로 전파되는 단계
  2. 타깃 단계 – 이벤트가 실제 타깃 요소에 전달되는 단계
  3. 버블링 단계 – 이벤트가 상위 요소로 전파되는 단계

테이블 안의를 클릭했을 때 발생하는 이벤트 흐름도

Capture Phase(1) -를 클릭하면 이벤트가 최상위 조상에서 시작해 아래로 전파. (캡처링)
Target Phase(2) -이벤트가 타깃 요소에 도착해 실행 됨. (타깃)
Bubbling Phase(3) -다시 위로 전파. (버블링)

이런 과정을 통해 요소에 할당된 이벤트 핸들러가 호출된다.

캡쳐링 단계를 이요해야 하는 경우는 흔치않다.

addEventListener(event, handler)를 이용해 할당된 핸들러는 capture 옵션을 true로 설정함으로써
캡처링 단계에서 이벤트를 잡아낼 수 있다.

capture 옵션을 설정하는 방법

1. element.addEventListener( ... , { capture: true } );
2. element.addEventListener( ... , true );

false(dafault) 일 때 : 핸들러가 버블링 단계에서 동작.
true 일 때 : 핸들러가 캡처링 단계에서 동작.

예시

직접 확인 :plnkr.co/plunk/ZSAnfZIotT98LScC

문서의 모든 요소에 핸들러를 할당했다.

를 클릭하면 다음과 같은 순서로 이벤트가 전달 된다.

  1. HTML→BODY→FORM→DIV(캡처링 단계, 첫 번째 리스너)
  2. P(타깃 단계, 캡쳐링과 버블링 둘 다에 리스너를 설정했기 때문에 두 번 호출됩니다.)
  3. DIV→FORM→BODY→HTML(버블링 단계, 두 번째 리스너)

*주의사항

출처 : ko.javascript.info/bubbling-and-capturing#ref-3448

반응형