
이벤트 핸들링을 하다보면 꼭 알아야 하는 이벤트 전파의 개념을 제대로 이해하기 위해 쓰는 글
: HTML 요소에서 이벤트가 발생했을 때, DOM에서 해당 이벤트가 다른 요소들에게 전달되는 방식을 의미한다.
DOM의 이벤트 전파는 크게 3가지 단계로 나뉘어진다.
캡처링(Capturing), 타켓(Target), 그리고 버블링(Bubbling)
이벤트 전파의 기본적인 순서는 캡처링 -> 타켓 -> 버블링의 순서로 진행된다.

첫 번째로 캡처링 단계는
이벤트가 최상위 요소(window or document)에서 시작해 이벤트가 발생한 요소까지 위에서 아래로 전달이 된다.
이는 부모 요소부터 자식 요소로 내려가는 flow다.
두 번째, 타켓 단계는
이벤트가 실제 이벤트가 발생한 요소에서 실행된다.
실제 이벤트가 발생한 요소가 Target
세 번째의 버블링 단계는
이벤트가 타켓 요소에서 시작해서 부모 요소로 전달한다.
자식 요소에서 부모 요소로 올라가는 아래-위 flow다.
기본적으로 버블링 단계에서 이벤트 핸들러가 실행이 된며, 이벤트 전파는 같은 이벤트일 때만 전파가 된다.
자식의 click 이벤트가 발생했을 때, 부모의 click 이벤트 핸들러가 실행이 된다.
부모의 다른 이벤트(Ex. scroll) 핸들러는 실행되지 않음
먼저 부모-자식의 요소로 구성된 HTML 예시부터 확인해보자.

위와 같이 DOM이 구성되어 있을 때, click에 대한 이벤트 핸들러 예시를 확인해보자

위의 코드로 구성이 되어있을 때, Child라는 div를 클릭하게 되면 아래와 같은 결과가 나타난다.

해당 이벤트가 일어난 요소의 클릭 핸들러
그 요소의 상위에 있는 parent의 클릭 핸들러
위에 예시에서의 최상위 요소인 grandparent의 클릭 핸들러
순서대로 이벤트 버블링이 이루어진다.
위에서 얘기했듯이, 이벤트 핸들러는 버블링 단계에서 실행이 된다.
이를 캡처링 단계에서 실행하려면, addEventListener의 세 번째 인자로 true를 전달해주면 된다!

위의 코드 예시와 캡처링을 위해 추가한 true를 합쳐서
Child 요소를 다시 클릭해보면 어떤 결과가 나올까?
결과는 아래와 같다.
(grandparent와 parent의 addEventListener에 true를 설정해준 결과)

Child 요소를 누르게 되면, 상위 요소들에서 캡처링을 true로 설정해줬기에 상위 요소에서 아래로 흘러가는 흐름이 먼저 발생한다.
상위 요소의 클릭 이벤트 핸들러가 실행이 되고, 밑으로 쭉쭉 발생하며 실제 이벤트가 발생한 요소의 이벤트 핸들러가 진행된다.

그런 다음, 이벤트 버블링이 실행되기에 true로 설정하지 않았던 상위 요소의 클릭 이벤트 핸들러가 순서대로 올라가며 실행이 된다.

하지만, 이벤트 캡처링을 true로 설정하는 일은 드물며 대부분 버블링 단계가 더 많이 사용이 된다.
(일반적으로 이벤트가 자식 요소에서 발생하고 부모로 전파되는 버블링 방식이 자연스럽고 필요한 동작을 처리하기 쉽기 때문)
이러한 이벤트 전파로 인해, 계속적으로 상위 요소의 이벤트 핸들러도 같이 실행이 되는 것이 방해가 될 때가 있다!
이벤트 전파를 막기 위해 event.stopPropagation() 메서드를 사용하여 특정 단계에서 이벤트 전파를 중단시킬 수 있다.
(이 메서드는 이벤트가 발생한 요소에서 상위 또는 하위 요소로 전파되지 않도록 해줌)
실제 이벤트가 발생할 요소에서만 이벤트 핸들러가 실행되게 하려면,
아래와 같이 이벤트 핸들러를 정의해주면 된다.

이렇게 event.stopPropagation() 메서드를 사용하면, 부모나 조부모의 클릭 이벤트 핸들러는 실행이 되지 않는다.
지난 프로젝트를 하며, 클릭 이벤트를 테스트하다 이벤트 전파를 눈으로 직접 겪게 되었다.
왜 이걸 클릭했는데 이것까지 클릭이 되나 싶었는데,
알고보니 이벤트 전파가 되어서 그랬던 것이었다.
알고만 있던 개념을 눈으로 직접 확인해보면 한번 더 체감이 되는 거 같아서 좋다 :)