프론트엔드/JavaScript

자바스크립트 - 이벤트 버블링과 캡쳐링

ksge7 2020. 10. 20. 10:37

자바스크립트에서 이벤트를 실행하면 버블링과 캡쳐링이란 것을 발생하게 할 수 있다.

 

간단하게 말하자면 이벤트가 발생 시 HTML 문서 구조상 이벤트가 다른 문서로 전이되는 것을 말한다.

 

코드를 살펴보자.

1. 캡쳐링과 버블링

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body id="body">
    <div id="div">
        <p id="p">
            <button id="btn"> 캡쳐링과 버블링 </button>
        </p>
    </div>
</body>
<script>
    let button = document.getElementById("btn");
    let p = document.getElementById('p');
    let div = document.getElementById('div');
    let body = document.getElementById('body');

    function ftest(){
        console.log("일어난 이벤트: "+event.target.nodeName+" 이벤트가 일어나는 현재 노드: "+this.nodeName);
    }

    btn.addEventListener('click', ftest, true);
    p.addEventListener('click', ftest, true);
    div.addEventListener('click', ftest, true);
    body.addEventListener('click', ftest, true);

</script>
</html>

 

위 코드를 살펴보자.

 

대략 그림으로 위 HTML문서의 구조를 나타내면 다음과 같다.

 

 

이때 여기서 버튼을 누르면 어떤 결과가 나올까?

 

다음과 같은 결과가 나온다.

 

버튼은 한번만 눌렀는데 결과값은 4개가 나온 것이다.

 

HTML 문서의 각 노드들은 어딘가 종속되어있는 계층적 구조로 이뤄진다.

 

그래서 어느 한 곳에서 이벤트가 발생하면 다른 곳으로 이벤트가 전파된다.

 

그리고 이때 이 이벤트가 전파되는 방향에 따라 이것을 캡쳐링과 버블링이라고 부르는 것이다.

 

둘은 구분하면 다음과 같다.

 

캡쳐링: 자식 요소에서 발생한 이벤트가 부모 요소에서 시작해 이벤트가 발생한 자식 요소까지 도달하는 것

버블링: 자식 요소에서 발생한 이벤트가 부모 요소로 전파되는 것

 

그림으로 나타내면 다음과 같다.

 

 

위 코드는 캡쳐링을 나타내는 코드로서 실행 결과는 다음과 같다.

 

캡쳐링은 아래와 같이 <body> - <div> - <p> - <button> 순으로 이벤트가 실행된다.

 

 

버블링 코드는 아래와 같다.

 

둘의 차이는 addEventListener 메서드를 실행할 때 3번째 파라미터 값으로 true/false 중 어떤 것을 주느냐의 차이다.

 

참고로 false가 디폴트값이고 이는 버블링을 나타낸다.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body id="body">
    <div id="div">
        <p id="p">
            <button id="btn"> 캡쳐링과 버블링 </button>
        </p>
    </div>
</body>
<script>
    let button = document.getElementById("btn");
    let p = document.getElementById('p');
    let div = document.getElementById('div');
    let body = document.getElementById('body');

    function ftest(){
        console.log("버블링:" + " 일어난 이벤트: "+event.target.nodeName+" 이벤트가 일어나는 현재 노드: "+this.nodeName);
    }

    btn.addEventListener('click', ftest, false);
    p.addEventListener('click', ftest, false);
    div.addEventListener('click', ftest, false);
    body.addEventListener('click', ftest, false);

</script>
</html>

 

버블링은 아래와 같이 <button> - <p> - <div> - <body> 순으로 이벤트가 실행된다.

 

2. 버블링과 캡쳐링 중단시키기

버블링, 캡쳐링은 HTML 구조상 자연스럽게 생기는 이벤트의 전파다.

 

그러나 이벤트 진행상 버블링이나 캡쳐링을 중단해야할 상황도 있다.

 

그럴 때는 'stopPropagation()' 메서드를 사용하면 된다.

 

이 때 'stopPropagation' 메서드는 'event' 객체를 이용해서 호출해주면 된다.

 

참고로 'event' 객체란 이벤트 핸들러를 이용해서 이벤트 코드를 실행할 때 해당 핸들러에 전달되는 객체다.

 

이 'event' 객체를 이용하면 이벤트와 관련된 다양한 사항을 제어할 수 있다.

 

코드는 다음과 같다.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body id="body">
    <div id="div">
        <p id="p">
            <button id="btn"> 캡쳐링과 버블링 </button>
        </p>
    </div>
</body>
<script>
    let button = document.getElementById("btn");
    let p = document.getElementById('p');
    let div = document.getElementById('div');
    let body = document.getElementById('body');

    function ftest(){
        console.log("버블링:" + " 일어난 이벤트: "+event.target.nodeName+" 이벤트가 일어나는 현재 노드: "+this.nodeName);
    }
    function stest(){
        console.log("버블링:" + " 일어난 이벤트: "+event.target.nodeName+" 이벤트가 일어나는 현재 노드: "+this.nodeName);
        event.stopPropagation();
    }

    btn.addEventListener('click', ftest, false);
    p.addEventListener('click', ftest, false);
    div.addEventListener('click', stest, false);
    body.addEventListener('click', ftest, false);

</script>
</html>

 

'stopPropagation'메서드가 추가된 메서드를 하나 더 만들어줘서 div 단계에서 버블링이 중단되게 했다.

 

 

실행 결과는 다음과 같다.

 

위 코드대로 'stopPropagation()' 메서드가 실행되는 <div> 태그까지만 이벤트가 실행되었다.