본문 바로가기
FE/JavaScript

[JavaScript] 이벤트

by thedev 2022. 11. 5.

 

이벤트

 


 

# 이벤트 등록

 

<div>click!</div>

 

const div = document.querySelector('div');
div.addEventListener('click', handleClick);

const handleClick = (event) => {
	console.log(event);
};

 

 화면에 동적인 기능을 추가하기 위해 addEventListener()로 이벤트를 등록할 수 있다. 사용자는 이를 통해 웹 페이지와 상호작용한다. 그렇다면 브라우저는 이벤트를 어떻게 감지할까? 브라우저가 이벤트를 감지하는 방법에는 두 가지가 있다.

 

 

# 이벤트 감지

 

1. 이벤트 버블링

 

 특정 요소에서 이벤트가 발생했을 때, 해당 요소의 상위 요소로 이벤트가 전파되는 것이다.

 

<body>
   <div class="one">
      <div class="two">
         <div class="three">클릭</div>
      </div>
   </div>
</body>

 

const divs = document.querySelectorAll("div");

const handleClick = (event) => {
  console.log(event.currentTarget.className);
};

divs.forEach((div) => {
  div.addEventListener("click", handleClick);
});

// 출력 결과
// three
// two
// one

 

 <div class="three">클릭</div>을 클릭하면 three, two, one이 모두 출력된다. 하나의 div만 클릭했지만 3개의 이벤트가 발생한 것이다. 이는 브라우저가 이벤트를 감지하는 방식 때문이다.

 

 위 예시에서는 각 태그마다 이벤트가 등록되어 있다. (forEach로 모든 div에 이벤트를 넣음) 이런 상황에서 브라우저는 특정 요소에서 이벤트가 발생했을 때, 그 이벤트를 최상위 요소까지 전파하는 특징이 있다. 따라서 three, two, one 순서로 이벤트가 실행된 것이다. 이렇게 하위 요소에서 상위 요소로 이벤트가 전파되는 것을 이벤트 버블링이라고 한다.

 

 

2. 이벤트 캡쳐

 

 이벤트 버블링과 반대로, 상위 요소에서 하위 요소로 이벤트가 전파되는 것이다.

 

<body>
   <div class="one">
      <div class="two">
         <div class="three">클릭</div>
      </div>
   </div>
</body>

 

const divs = document.querySelectorAll("div");

const handleClick = (event) => {
  console.log(event.currentTarget.className);
};

divs.forEach((div) => {
  div.addEventListener("click", handleClick, { capture: true });
});

// 출력 결과
// one
// two
// three

 

 addEventListener()의 옵션으로 capture: true를 설정해주면 이벤트 캡쳐를 구현할 수 있다. 이렇게 하면 브라우저는 이벤트 버블링과 반대 방향으로 이벤트를 감지한다. 따라서 one, two, three 순서로 출력된다.

 

 

# 이벤트 전파 막기 : event.stopPropagation()

 

 이벤트의 전파를 막고 싶다면 event.stopPropagation()을 이용하면 된다. 이벤트의 전파를 막아주는 API이다.

 

const divs = document.querySelectorAll("div");

const handleClick = (event) => {
  event.stopPropagation();
  console.log(event.currentTarget.className);
};

divs.forEach((div) => {
  div.addEventListener("click", handleClick);
});

// 출력 결과
// three

 

const divs = document.querySelectorAll("div");

const handleClick = (event) => {
  event.stopPropagation();
  console.log(event.currentTarget.className);
};

divs.forEach((div) => {
  div.addEventListener("click", handleClick, { capture : true });
});

// 출력 결과
// one

 

 이벤트 버블링에서 event.stopPropagation()를 사용하면 클릭한 요소의 이벤트만 발생하고, 이벤트 캡쳐에서 이를 사용하면 최상위 요소의 이벤트만 발생한다.

 

 

# 이벤트 위임

 

 위에서 설명한 이벤트 감지 방식을 이용하여 '하위 요소에 하나하나 이벤트를 붙이지 않고 상위 요소에서 하위 요소 이벤트를 관리하는 방식'을 구현할 수 있다. 

 

<ul class="list">
   <li><div class="item1">item1</div></li>
   <li><div class="item2">item2</div></li>
   <li><div class="item3">item3</div></li>
</ul>

 

const list = document.querySelector(".list");

list.addEventListener("click", (event) => {
  console.log(event.target.className);
});

 

 <li></li> 요소 하나하나에 모두 addEventListener()를 다는 것보다, 상위 요소인 <ul class="list"></ul>에 한 번만 이벤트를 등록하는 것이 훨씬 효율적이다. 상위 요소 하나에 이벤트 리스너를 달아놓았기 때문에, 하위 요소에서는 클릭 이벤트를 감지할 수 있다. 이렇게 이벤트 전파 특징을 이용하면 코드를 효율적이게 작성할 수 있다.

 


 

addEventListener 공부할 때마다 나오는 개념이길래 한 번 정리하고 감😮

 

참고 자료

https://joshua1988.github.io/web-development/javascript/event-propagation-delegation/