Event Bubbling / Capturing

Happhee·2022년 3월 10일
3

 💜 JavaScript 💜

목록 보기
4/19
post-thumbnail

Event Delegation의 속성을 활용하여 Vanila JS를 구현해보는 과정에서 이벤트 버블링과 캡쳐에 대한 지식이 정리가 되어있지 않음을 느껴 이 글을 작성하게 되었다.


✨ 이벤트란?

클릭이나 스크롤을 내리는 등 사용자와 웹페이지가 상호작용하며 브라우저가 감지하는 것을 말한다.

이벤트 리스너, 이벤트 핸들러가 바로 이벤트를 발생할 때, 처리하는 함수이며
자주 사용하는 DOM 이벤트click, contextmenu, keydown, keyup, focus등이 있다.


✨ 이벤트 등록

앞서 말한 이벤트를 발생시키기 위해서는 이벤트 등록이라는 절차가 필요하며, 대표적인 함수가 addEventListener() 웹 API이다.

예제 코드를 살펴보자 👇

<input type="checkbox" id="item">
let input = document.querySelector('input');
input.addEventListener('click', function(){
	alert('clicked');
})

checkbox의 타입을 가지고 있는 input 태그에 'click'이라는 이벤트를 추가하고, 해당 태그를 선택할 때, 브라우저가 이벤트를 감지하고 alert( )창을 띄워준다.

어떻게 브라우저가 이벤트를 감지할 수 있는 걸까??


✨ Event Bubbling

특정 화면 요소에서 이벤트가 발생했을 때, 해당 이벤트가 더 상위의 화면 요소들로 전달되어 가는 특성을 의마한다.

  • 여기서 상위의 화면요소란?
    HTML은 트리 구조를 갖기 때문에, 이 구조 상에서 한 단계 위에 있는 요소를 상위요소라고 부르며 body태그를 최상위 요소로 부른다.

예제 코드로 이를 파악해보자👇

<body>
  <div class="one">
    <div class="two">
      <div class="three">
      </div>
    </div>
  </div>
</body>
let divs = document.querySelectorAll('div');
divs.forEach(function(div){
	div.addEventListener('click', function(e){
    	console.log(e.currentTarget.className);
    });
});

<div class="three"><div>을 선택하면, three -> two -> one으로 콘솔에 로그가 찍힌다.
이는 브라우저가 이벤트를 감지하는 방식 때문에 발생하는 현상이다.

브라우저는 특정 화면 요소에서 이벤트가 발생했을 때, 그 이벤트를 최상위에 있는 화면 요소까지 전달시키는 특징을 가지고 있다.
만약, three가 아닌 two를 선택했다면, two -> one으로 콘솔에 로그가 찍힐 것이다.

하위요소에서 상위 요소로의 이벤트 전파 방식을 이벤트 버블링이라고 하는 것이다.


✨ Event Capturing

이벤트 버블링과 반대로 진행되는 방식이 Event Capturting이다.

예제 코드로 이를 파악해보자👇

<body>
  <div class="one">
    <div class="two">
      <div class="three">
      </div>
    </div>
  </div>
</body>
let divs = document.querySelectorAll('div');
divs.forEach(function(div){
	div.addEventListener(
      'click', 
      function(e){
    	console.log(e.currentTarget.className);
      }),  
      true // default 값은 false입니다.
  );
});

addEventListener( )의 마지막 인자로 true를 전달하면, 이벤트 캡처링이 발생한다.
즉, three를 선택했을때, one -> two -> three으로 콘솔에 로그가 찍힌다.


✨ Event Delegation

이벤트 버블링과 캡처링을 사용한 개념이 이벤트 위임이다.

하위 요소에 각각 이벤트를 붙이지 않고, 상위 요소에서 하위 요소의 이벤트들을 제어하는 방식이다.

예제코드

<body>
    <h1>이벤트 버블링 / 캡쳐 학습</h1>
    <ul class="itemList">
      <li>
        <input type="checkbox" id="item1" />
        <label for="item1">이벤트 버블링 </label>
      </li>
      <li>
        <input type="checkbox" id="item2" />
        <label for="item2">이벤트 캡쳐 </label>
      </li>
    </ul>
  </body>

input을 선택했을 때, alert창이 뜨게 하는 코드이다.

let inputs = document.querySelector("input");
    inputs.addEventListener("click", function (e) {
     alert('clicked');
    });

여기서 li 에 input과 label를 추가하자.

   let itemList = document.querySelector(".itemList");
   let li = document.createElement("li");
   let input = document.createElement("input");
   let label = document.createElement("label");
   let labelText = document.createTextNode("이벤트 위임 학습");

   input.setAttribute("type", "checkbox");
   input.setAttribute("id", "item3");
   label.setAttribute("for", "item3");
   label.appendChild(labelText);
   li.appendChild(input);
   li.appendChild(label);
   itemList.appendChild(li);

하지만, 새로 추가한 리스트 아이템에는 클릭 이벤트가 작동되지 않는다.
왜? 인풋 박스에 이벤트 리스너를 추가하는 시점에 리스트 아이템이 두 개이기 때문이다.

이러한 문제를 해결하기 위해서 우리는 이벤트 위임을 사용해야 하는 것이다.

해결한 코드는 아래와 같다.👇

let itemList = document.querySelector(".itemList");
itemList.addEventListener("click", function (e) {
      alert('clicked');
    });

화면의 모든 인풋 박스에 이벤트 리스너를 추가하는 방식 대신, 인풋 박스의 상위 요소인 ul에 이벤트 리스너를 달아 하위에서 발생한 이벤트를 감지하는 방식을 사용하는 것이다.

다만, 해당코드는 input과 label 둘 다 이벤트를 감지하므로 input 박스의 이벤트와 감지하기 위해서는 event 객체를 이용하는 것이 필요하다.

itemList.addEventListener("click", function (e) {
  if (e.target.tagName === "INPUT") {
    console.log("clicked");
  } else e.preventDefault();
});

target.tagName을 활용하여 이벤트를 발생시키고, label일 경우 이벤트 발생 자체를 막는 e.preventDefault() 메서드를 사용하여 문제를 해결하였다.


❗️ event.target VS event.currentTarget ❗️

event.targetevent.currentTarget (this)
실제 이벤트가 시작된 ‘타깃’ 요소‘현재’ 요소
버블링이 진행되어도 변하지 않는다.현재 실행 중인 핸들러가 할당된 요소를 참조

📚 학습할 때, 참고한 자료 📚

📄 예제코드 📄

profile
즐기면서 정확하게 나아가는 웹프론트엔드 개발자 https://happhee-dev.tistory.com/ 로 이전하였습니다

2개의 댓글

너무 멋있어요...

답글 달기
comment-user-thumbnail
2023년 4월 25일

이벤트 버블링에 대해 쉽게 설명해주신 글인 것 같아요 잘 배우고 갑니다~

답글 달기