Javascript/Javascript 지식

이벤트 버블링/캡쳐/위임

덕구공 2022. 9. 16. 10:05

이벤트 버블링 (Event Bubbling)

  • 어떠한 특정 요소에서 이벤트가 발생하면 이 요소에 할당된 이벤트가 실행되고 가장 먼 조상까지 해당 이벤트가 전파되는 특성이다.
  • 예를 HTML 마크업이 a > div > span와 같고 a, div, span을 모두 클릭 시 alert가 나타나는 이벤트를 가지고 있다하면 span 태그를 클릭하면 span < div < a 순으로 이벤트가 전파된다.
  • 아래 예시를 통해 좀 더 살펴보자!
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>버블링 & 캡쳐링</title>
    <style>
        div {
            margin: 16px;
            border: 2px solid blue;
            text-align: center;
            font-size: 2rem;
            font-weight: bold;
        }
    </style>
    <script>
        window.onload = () => {
            var a = document.getElementById("a");
            var b = document.getElementById("b");
            var c = document.getElementById("c");
            a.addEventListener('click', function (e) {
                alert(a.innerText);
            });
            b.addEventListener('click', function (e) {
                alert(b.innerText);
            });
            c.addEventListener('click', function (e) {
                alert(c.innerText);
            });
        }
    </script>
</head>

<body>
    <div id="a">a
        <div id="b">b
            <div id="c">c</div>
        </div>
    </div>
</body>

</html>
  • 제일 하위 태그의 이벤트를 발생시키면 가장 먼 조상까지 이벤트가 전파된다.

이벤트 캡쳐 - Event Capture

  • 이벤트 버블링과 반대로 어떠한 특정 요소에서 이벤트 발생하면 이 요소에 할당된 이벤트가 실행되고 가장 먼 자손 까지 해당 이벤트가 전파되는 특성이다.
  • 예를 HTML 마크업이 a > div > span와 같고 a, div, span을 모두 클릭 시 alert가 나타나는 이벤트를 가지고 있다하면 span 태그를 클릭하면 a < div < span 순으로 이벤트가 전파된다.
  • 아래 예시를 통해 좀 더 살펴보자!
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>버블링 & 캡쳐링</title>
    <style>
        div {
            margin: 16px;
            border: 2px solid blue;
            text-align: center;
            font-size: 2rem;
            font-weight: bold;
        }
    </style>
    <script>
        window.onload = () => {
            var a = document.getElementById("a");
            var b = document.getElementById("b");
            var c = document.getElementById("c");
            a.addEventListener('click', function (e) {
                alert(a.innerText);
            }, {capture: true});
            b.addEventListener('click', function (e) {
                alert(b.innerText);
            }, {capture: true});
            c.addEventListener('click', function (e) {
                alert(c.innerText);
            }, {capture: true});
        }
    </script>
</head>

<body>
    <div id="a">a
        <div id="b">b
            <div id="c">c</div>
        </div>
    </div>
</body>

</html>
  • 이벤트 버블링과 반대로 이벤트가 전파되면서 alert가 찍히는 것을 확인할 수 있다!

이벤트 위임 (event delegation)

  • 캡처링과 버블링을 활용하면 강력한 이벤트 핸들링 패턴인 이벤트 위임(event delegation) 을 구현할 수 있다.
  • 여러 엘리먼트마다 각각 이벤트 핸들러를 할당하지 않고, 공통되는 부모에 이벤트 핸들러를 할당하여 이벤트를 관리하는 방식이다
  • 동적으로 추가되거나 삭제되는 엘리먼트에 대해 매번 이벤트 리스너를 추가하고 삭제한다면 코드의 효율성도 문제이며, 제대로 리스너가 삭제되지 않을 수도 있으므로 메모리 누수 가능성도 커진다.
  • 예를들어 아래 id가 parent인 div 태그 안에 추가로 d, e, ... 가 innerText인 태그를 삽입하고 추가된 태그를 클릭했을 때 innerText를 출력하는 이벤트를 달아준다고 할 때, 일일이 하나씩 달아줘야 한다.
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>버블링 & 캡쳐링</title>
    <style>
        div {
            margin: 16px;
            border: 2px solid blue;
            text-align: center;
            font-size: 2rem;
            font-weight: bold;
        }
    </style>
    <script>
        window.onload = () => {
            var a = document.getElementById("a");
            var b = document.getElementById("b");
            var c = document.getElementById("c");
            a.addEventListener('click', function (e) {
                alert(a.innerText);
            });
            b.addEventListener('click', function (e) {
                alert(b.innerText);
            });
            c.addEventListener('click', function (e) {
                alert(c.innerText);
            });
        }
    </script>
</head>

<body>
    <div id="parent">
        <div id="a">a</div>
        <div id="b">b</div>
        <div id="c">c</div>
    </div>
</body>

</html>
  • 하지만 아래처럼 id가 parent인 태그에 이벤트를 위임하면 동적으로 자식들이 추가될 때 이벤트를 따로 추가해주지 않아도 된다!
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>버블링 & 캡쳐링</title>
    <style>
        div {
            margin: 16px;
            border: 2px solid blue;
            text-align: center;
            font-size: 2rem;
            font-weight: bold;
        }
    </style>
    <script>
        window.onload = () => {
            var parent = document.getElementById("parent");
            parent.addEventListener('click', function (e) {
                alert(e.target.innerText);
            });
        }
    </script>
</head>

<body>
    <div id="parent">
        <div id="a">a</div>
        <div id="b">b</div>
        <div id="c">c</div>
    </div>
</body>

</html>

++ React 이벤트 살펴보기

  • jQuery나 일반적인 자바스크립트에서는 DOM노드에 직접 이벤트 리스너를 연결하지만, React에서는 다른 방법으로 이벤트를 처리한다.
  • 더 나은 방법은 부모요소에 하나의 이벤트 리스너를 두고, 버블링되는 이벤트를 처리하는 것이다 (이벤트를 하위요소에서 처리하지 않으면 DOM트리를 따라 위로 버블링 된다.) React는 내부적으로 상위 요소 및 대상 요소에 연결된 이벤트를 매핑에서 추적한다.
  • 리액트는 이벤트 리스너를 최상위 부모인 document 요소에 연결했다. → 이벤트 위임