이벤트 버블링이란 ?

GonnabeAlright·2021년 11월 29일
0
post-thumbnail

이벤트 버블링 - Event Bubbling

이벤트 버블링은 특정 화면 요소에서 이벤트가 발생했을 때 해당 이벤트가 더 상위의 화면 요소들로 전달되어가는 특성을 의미합니다.

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

실행결과 (최하위 div 태그<div class="three"></div> 클릭)

three
two
one

브라우저는 특정 화면 요소에서 이벤트가 발생했을 때 그 이벤트를 최상위에 있는 화면 요소까지 이벤트를 전파시킵니다. 따라서 클래스명 three -> two -> one 순서로 div 태그에 등록된 이벤트들이 실행되었습니다.

각 태그마다 이벤트가 등록되어 있기 때문에 상위 요소로 이벤트가 전달되는 것을 확인할 수 있습니다. 만약 이벤트가 특정 div 태그에만 달려 있다면 위와 같은 동작 결과는 확인할 수 없습니다.

이와 같이 하위에서 상위 요소로의 이벤트 전파 방식을 이벤트 버블링(Event Bubbling)이라고 합니다.

이벤트 캡쳐 - Event Capture

이벤트 캡쳐는 이벤트 버블링과 반대 방향으로 진행되는 이벤트 전파 방식입니다.

<body>
  <div class="one">
    <div class="two">
      <div class="three">
      </div>
    </div>
  </div>
</body>
var divs = document.querySelectorAll('div');
divs.forEach(function(div) {
  div.addEventListener('click', logEvent, {
    capture: true		// default 값은 false
  });
});
function logEvent(event) {
 console.log(event.currentTarget.className); 
}

addEventListener() API에서 옵션 객체에 capture: true로 설정할 경우 해당 이벤트를 감지하기 위해 이벤트 버블링과 반대 방향으로 탐색합니다.

실행결과 (최하위 div 태그 <div class="three"></div> 클릭)

one
two
three

event.stopPropagation()

이 API는 해당 이벤트가 전파되는 것을 막습니다. 따라서, 이벤트 버블링의 경우에는 클릭한 요소의 이벤트만 발생시키고 상위 요소로 이벤트를 전달하는 것을 방해합니다. 그리고 이벤트 캡쳐의 경우에는 클릭한 요소의 최상위 요소의 이벤트만 동작시키고 하위 요소들로 이벤트를 전달하지 않습니다.

divs.forEach(function(div) {
  div.addEventListener('click', logEvent);
});
function logEvent(event) {
  event.stopPropagation();
  console.log(event.currentTarget.className);	// three
}
divs.forEach(function(div) {
  div.addEventListener('click', logEvent, {
    capture: true
  });  
});
function logEvent(event) {
  event.stopPropagation();
  console.log(event.currentTarget.className);	// one  
}

이벤트 위임 - Event Delegation

이벤트 위임은 실제 바닐라 JS로 웹 앱을 구현할 때 자주 사용하게 되는 코딩 패턴입니다.
이벤트 위임을 한 문장으로 요약하면 '하위 요소에 각각 이벤트를 붙이지 않고 상위 요소에서 하위 요소의 이벤트들을 제어하는 방식'입니다.

<h1>오늘의 할 일</h1>
<ul class="itemList">
  <li>
    <input type="checkbox" id="item1">
    <label for="item1">이벤트 버블링 학습</label>    
  </li>
  	<input type="checkbox" id="item2">
    <label for="item2">이벤트 캡쳐 학습</label>
  <li>
</ul>
var inputs = document.querySelectorAll('input');
inputs.forEach(function(input) {
  input.addEventListener('click', function(event) {
    alert('clicked');
  });
});

+ 리스트 아이템 추가

var itemList = document.querySelector('.itemList');
var li = documet.createElement('li');
var inpur = document.createElement('input');
var label = document.createElement('label');
var 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);

새로 추가된 리스트 아이템에는 클릭 이벤트 리스너가 동작하지 않는다.
인풋 박스에 클릭 이벤트 리스너를 추가하는 시점에서 리스트 아이템은 두 개이다.
따라서, 새롭게 추가된 리스트 아이템에는 클릭 이벤트 리스너가 등록되지 않았다. 이런식으로 매번 새롭게 추가된 리스트 아이템까지 클릭 이벤트 리스너를 일일이 다는 것은 번거로우니 이벤트 위임(Event Delegation)을 사용해 이벤트를 등록해줄 것이다.

// var inputs = document.querySelectorAll('input');
// inputs.forEach(function(input) {
//   input.addEventListener('click', function() {
//     alert('clicked');
//   });
// });
var itemList = document.querySelector('.itemList');
itemList.addEventListener('click', function(event) {
  alert('clicked');
});

화면의 모든 인풋 박스에 일일이 이벤트 리스너를 추가하는 대신 이제는 인풋 박스의 상위 요소인 ul태그 .itemList에 이벤트 리스너를 달아놓고 하위에서 발생한 클릭이벤트를 감지합니다.

event.target vs event.currentTarget

event.target이벤트 버블링의 가장 마지막에 위치한 최하위의 요소를 반환(클릭된 요소를 기준으로 사용할 경우 주로 사용)

event.currentTarget이벤트가 바인딩된 요소, 해당하는 요소를 반환

0개의 댓글