날쌘 개발자

[JavaScript] 이벤트 버블링과 캡처링 본문

web/JavaScript

[JavaScript] 이벤트 버블링과 캡처링

훈식이 2024. 8. 5. 17:02
728x90

교육을 듣던중, 분명히 수없이 써왔던 개념이지만 용어 자체는 낯선.. 부분이 있어서 제대로 알아가고 싶어 정리해보려 한다.
자바스크립트의 DOM 이벤트 모델에서 중요한 개념인 버블링 / 이벤트 캡처링 이다.

 

먼저 이벤트 전파 단계(Event Prepagation Phases)에 관하여 간단하게 알아보자면,
브라우저에서 이벤트가 발생했을 때 이벤트가 전파되는 순서를 의미한다. 이벤트 전파단계는 아래의 세 가지 단계로 나뉜다.

  1. 캡처링 단계 - 이벤트가 최상위 요소에서 타겟 요소로 내려가는 단계.
  2. 타겟 단계 - 이벤트가 실제로 발생한 요소에서 실행되는 단계.
  3. 버블링 단계 - 이벤트가 타겟 요소에서 시작하여 최상위 요소로 올라가는 단계.

이벤트 버블링

특정 요소에 이벤트가 발생했을 때, 그 이벤트가 해당 요소에서 시작하여 부모 요소들을 거쳐 최상위 요소 까지 전파되는데, 이 방식을 이벤트 버블링(Bubbling) 이라고 한다.
참고로 이벤트 캡처링은 위와 반대방향으로 진행되는 유사한 개념이라고 보면 된다.

 

코드를 예시로 간단하게 알아보자면,

    <div class="outer">
        <div class="middle">
            <div class="inner"></div>
        </div>
    </div>

    <script>
        document.querySelector('.outer').addEventListener('click', () => {
            console.log('Outer DIV clicked');
        });

        document.querySelector('.middle').addEventListener('click', () => {
            console.log('Middle DIV clicked');
        });

        document.querySelector('.inner').addEventListener('click', () => {
            console.log('Inner DIV clicked');
        });
    </script>

해당 코드를 실행한 후 .inner 요소를 클릭하면 다음과 같은 순서로 콘솔에 메시지가 출력된다.

 

 

각 요소에는 핸들러가 할당되어 있으므로, 가장 먼저 해당 요소에 할당된 핸들러가 동작 한 후, 최상위 document 객체를 만날 때 까지 부모요소의 핸들러가 동작하는 것이다.
쉽게 말하자면 이벤트가 발생한 요소에서 시작하여 부모 요소들을 거쳐 최상위 요소까지 전파되는 과정이다.


이러한 버블링은 몇몇 특정 이벤트들을 제외한 거의 대부분의 이벤트에서 발생한다.


이벤트 캡처링

위에서 설명한 이벤트 버블링 과는 반대 방향의 유사한 개념으로,
이벤트가 최상위 요소 (document 혹은 window) 에서 시작하여 이벤트가 발생한 타겟 요소로 내려가는 과정이다.
이벤트 버블링 은 자주 활용되는 반면 이벤트 캡처링은 흔히 사용되지는 않지만, 종종 유용한 경우가 있다고하니 알아두어서 나쁠건 없을것 같다.

 

이벤트 캡처링을 코드로 한번 시각화해서 알아보자. 아까와 유사한 코드이지만, 이벤트 리스너의 세 번재 인자를 'true' 로 설정하였다.

    <div class="outer">
        <div class="middle">
            <div class="inner"></div>
        </div>
    </div>

    <script>
        document.querySelector('.outer').addEventListener('click', () => {
            console.log('Outer clicked');
        }, true);

        document.querySelector('.middle').addEventListener('click', () => {
            console.log('Middle clicked');
        }, true);

        document.querySelector('.inner').addEventListener('click', () => {
            console.log('Inner clicked');
        }, true);
    </script>

 

해당 코드를 실행한 후 마찬가지로 .inner 를 클릭하면 결과는 아래와 같다.

 

 

아까의 이벤트 버블링을 알아보는 코드에서 매개변수 하나를 지정했을 뿐인데, 결과는 거꾸로 나왔다.

이는 'addEventListener' 메서드의 세 번째 인자인 boolean 값을 이용한 방식이다.


이 세번째 인자로 true 를 전달하면 캡처링 단계에서 이벤트 리스너가 실행되며,
default값인 false 를 전달하면 버블링 단계에서 이벤트 리스너가 실행된다.


이벤트 전파 제어하기

버블링/캡처링을 중단하는 방법도 있는데,
stopPropagation() 메서드를 사용하면 이벤트 버블링을 끊어버릴 수 있다.

document.querySelector('.inner').addEventListener('click', (event) => {
    console.log('Inner DIV clicked');
    event.stopPropagation();
});

이런식으로 메서드를 호출해주면, .inner 를 클릭해도 'Middle DIV clicked' , 'Outer DIV clicked' 메시지는 출력되지 않는다.
다만 이 방식은 실행되어야 할 다른 이벤트 핸들러의 동작을 막는 등의 예상치 못한 문제를 일으키기 쉽기 때문에, 사용할때는 항상 신중하게 부작용을 고려해보아야 한다.

 

 

 

참고 링크

https://ko.javascript.info/bubbling-and-capturing#ref-166
https://developer.mozilla.org/ko/docs/Web/API/Event/eventPhase

728x90