이벤트 버블링과 캡처링 그리고 이벤트 위임

devstone·2021년 5월 29일
13

Javascript Study

목록 보기
1/5
post-thumbnail

🙈 목차

  1. 이벤트의 발생 단계
  2. 이벤트 캡처링
  3. 이벤트 버블링
  4. 이벤트 위임

1. 이벤트의 발생 단계

표준 DOM 이벤트에서 정의한 이벤트 흐름은

  1. 캡처링 단계 - 이벤트가 하위 요소로 전파
  2. 타깃 단계 - 이벤트가 실제 타깃 요소에 전달
  3. 버블링 단계 - 이벤트가 상위 요소로 전파

위 세 단계로 이뤄집니다!
각 단계를 하나하나 상세하게 보겠습니다.

2. 이벤트 캡처링

  • 이벤트가 최상위 조상에서 시작해 아래로 전파되는 단계입니다. 그러나 이 단계를 이용해야하는 경우는 흔하지 않습니다
  • 캡처링 단계의 이벤트를 잡아내기 위해선 addEventListenrcapture 옵션을 임의로 true로 설정해야됩니다. (디폴트 값인 false는 이벤트 버블링을 잡아내지 못한다.)
elem.addEventListener(..., {capture: true})
// 아니면, 아래 같이 {capture: true} 대신, true를 써줘도 됩니다.
elem.addEventListener(..., true)

3. 이벤트 버블링

  • 한 요소에 이벤트가 발생하면 이 요소에 할당된 핸들러 동작 이후 부모 요소의 핸들러가 동작하는 것을 의미합니다.
  • 최상단 부모를 만날 때까지 동작하는데, 거의 모든 이벤트에 적용 되지만 focus와 같이 종종 버블링되지 않는 이벤트도 있습니다.
<style>
  body * {
    margin: 10px;
    border: 1px solid blue;
  }
</style>

<form onclick="alert('form')">
  FORM
  <div onclick="alert('div')">
    DIV
    <p onclick="alert('p')">P</p>
  </div>
</form>

그렇다면, 정확히 어떤 요소에서 이벤트가 발생했는지는 알기 위해서는 어떻게 해야할까요?
event.target 이용하면 됩니다!

  • event.target은 실제 이벤트가 시작된 ‘타깃’ 요소입니다. 실제 이벤트가 발생한 요소를 의미합니다. (이벤트 발생 위치)
  • event.currentTarget은 이벤트가 부착되어 있는 요소를 의미합니다. (이벤트 생성 위치)

🐢 이벤트 버블링 중단하기

  • event.stopPropagation()를 이용해 중단시킬 수 있습니다
<body onclick="alert(`버블링은 여기까지 도달하지 못합니다.`)">
  <button onclick="event.stopPropagation()">클릭해 주세요.</button>
</body>
  • 위 코드에선 onClick 이벤트가 버블링 되지 않고 오로지 button테그 에서만 실행됩니다.

그러나 이벤트 버블링 중단은 거의 사용하지 않고, 사용한 핸들러마저 죽은 이벤트가 되어버리기 때문에 섣불리 사용하면 위험합니다!

🐢 이벤트 캡처링과 버블링

아래 코드의 실행 양상을 살펴봄으로써 이벤트 캡처링과 버블링을 이해할 수 있습니다.

<form>
  FORM
  <div>
    DIV
    <p>P</p>
  </div>
</form>

<script>
  for (let elem of document.querySelectorAll("*")) {
    elem.addEventListener(
      "click",
      (e) => alert(`캡쳐링: ${elem.tagName}`),
      true
    );
    elem.addEventListener("click", (e) => alert(`버블링: ${elem.tagName}`));
  }
</script>

4. 이벤트 위임

캡처링과 버블링을 활용해 강력한 이벤트 핸들 방식인 이벤트 위임을 사용할 수 있습니다!

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

  • 사용방법

    1. 컨테이너에 하나의 핸들러를 할당합니다.
    2. 핸들러의 event.target을 사용해 이벤트가 발생한 요소가 어디인지 알아냅니다.
    3. 원하는 요소에서 이벤트가 발생했다고 확인되면 이벤트를 핸들링합니다.
<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>
let inputs = document.querySelectorAll("input");
inputs.forEach(function (input) {
  input.addEventListener("click", function (event) {
    alert("clicked");
  });
});
  • input테그를 클릭했을 때 'clicked'창이 뜨게 하려면 기존 방식대로는 하나하나 다 이벤트핸들러를 할당해야 합니다.
  • 그러나 아래의 방식대로 상위 테그인 ul에서 이벤트 위임을 이용하면 이벤트핸들러를 전부 할당하지 않고 이벤트를 적용시킬 수 있습니다!
let itemList = document.querySelector('.itemList');
itemList.addEventListener('click', function(event) {
	alert('clicked');
});

🐢 React에서의 이벤트 위임

  • React v17.0는 자체 이벤트 시스템을 갖기 때문에 이미 리액트가 관리하기 시작하는 div에서 이벤트를 잡아 자체적으로 처리합니다.
  • 때문에, 이미 성능상의 이득을 보는 방식으로 동작하므로 이벤트 위임을 통한 성능상의 이익은 없습니다

🙉 레퍼런스

레퍼런스는 쿠키파킹을 통해 확인할 수 있습니다~
https://www.cookieparking.com/share/U2FsdGVkX1_bVF5luMLe55H2Mdt7CkrBrjpTLSxZR7QnpTL3y0jB6NYQ_mOiaTbuUTzzjzWsVqeWiPgy4NvNIsQQ0z7rXjPOGiict_WkZyA

profile
개발하는 돌멩이

4개의 댓글

comment-user-thumbnail
2021년 6월 2일

정리 잘되어 있네요ㅎ 잘보고 갑니다~
감사합니다👍👍

1개의 답글
comment-user-thumbnail
2021년 6월 23일

도움 많이 됐네요 !! 양질의 글 감사합니다 :)

1개의 답글