JavaScript | 이벤트 버블링 / 캡쳐링

Kate Jung·2022년 8월 3일
0

JavaScript

목록 보기
36/39
post-thumbnail

📌 이벤트 흐름 3가지 단계

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

    테이블 안의 <td>를 클릭하면 어떻게 이벤트가 흐르는가?

    <td>를 클릭하면 이벤트가 최상위 조상에서 시작해 아래로 전파되고(캡처링 단계), 이벤트가 타깃 요소에 도착해 실행된 후(타깃 단계), 다시 위로 전파됩니다(버블링 단계).

📌 이벤트 버블링 (bubbling)

🔹 원리

한 요소에 이벤트가 발생 → 이 요소에 할당된 핸들러가 동작 → 부모 요소의 핸들러가 동작함.

가장 최상단의 조상 요소(몇 이벤트는 window 객체 그 외에는 document 객체)를 만날 때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작함.

🔹 특징

‘거의’ 모든 이벤트는 버블링 됨. (버블링 되지 않는 이벤트도(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>

https://run.plnkr.co/preview/cl6d6z5zz00033b70hmog5bgg/

  • 동작 원리

    가장 안쪽의 <p>를 클릭 시

    1. <p>에 할당된 onclick 핸들러가 동작.

    2. 바깥의 <div>에 할당된 핸들러가 동작.

    3. 그 바깥의 <form>에 할당된 핸들러가 동작.

    4. document 객체를 만날 때까지, 각 요소에 할당된 onclick 핸들러가 동작.

  • 동작 결과

    <p> 요소 클릭 시, p → div → form 순서로 3개의 alert 창 출현.

🔹 event.target

  • 타깃(target) 요소

    이벤트가 발생한 가장 안쪽의 요소

    • event.target으로 접근 가능
  • 부모 요소의 핸들러는 자세한 정보 얻기 가능.

    (이벤트가 정확히 어디서 발생했는지 등)

✦ event.target과 this의 차이점

event.targetthis (=event.currentTarget)
설명실제 이벤트가 시작된 ‘타깃’ 요소‘현재’ 요소
특징버블링이 진행되어도 안 변함.현재 실행 중인 핸들러가 할당된 요소를 참조
  • 예시

    • 상황

      핸들러는 form.onclick 하나밖에 없지만 이 핸들러에서 폼 안의 모든 요소에서 발생하는 클릭 이벤트를 ‘잡아내고(catch)’ 있음.

    • 이유

      클릭 이벤트가 어디서 발생했든 상관없이 <form> 요소까지 이벤트가 버블링 되어 핸들러를 실행시키기 때문

    • 실제 코드 & 실행

    • form.onclick 핸들러 내의 this와 event.target

      this (event.currentTarget)event.target
      가리키는 요소요소 (이유: 요소에 있는 핸들러가 동작해서)폼 안쪽에 실제 클릭한 요소
      • <form> 요소 클릭 시

        event.target === this

🔹 버블링 중단

event.stopPropagation() 활용

  • 핸들러에게 이벤트를 완전히 처리한 뒤, 버블링을 중단하도록 명령 가능

  • 예시

    <button>을 클릭해도 body.onclick은 동작 x

  • 꼭 필요한 경우를 제외하곤 버블링을 막지 말 것

    • 버블링은 유용함.

      버블링을 꼭 멈춰야 하는 명백한 상황이 아니라면 버블링을 막지 말 것.

    • 대안 有 (커스텀 이벤트 등을 사용)

    • 자세한 이유 참고 : 링크

  • event.stopImmediatePropagation()

    버블링을 멈추고, 요소에 할당된 다른 핸들러의 동작도 막으려면 사용

    • 이 메서드를 사용하면 요소에 할당된 특정 이벤트를 처리하는 핸들러 모두가 동작 x

    • 한 요소의 특정 이벤트를 처리하는 핸들러가 여러 개인 상황에서, 핸들러 중 하나가 버블링을 멈추더라도 나머지 핸들러는 여전히 동작

      event.stopPropagation()은 위쪽으로 일어나는 버블링은 막아주지만, 다른 핸들러들이 동작하는 건 못 막음.

📌 이벤트 캡쳐링

  • 캡처링 단계를 이용해야 하는 경우는 흔치 x

  • on<event>프로퍼티, HTML 속성, addEventListener(event, handler)를 이용해 할당된 핸들러

    → 캡처링에 대해 전혀 알 수 x

    • 2, 3 번째 단계의 이벤트 흐름(타깃 단계와 버블링 단계)에서만 동작

    • 캡처링 단계에서 이벤트를 잡아내려면

      addEventListener의 capture 옵션을 true로 설정

      elem.addEventListener(..., {capture: true})
      // 아니면, 아래 같이 {capture: true} 대신, true를 써줘도 됩니다.
      elem.addEventListener(..., true)
  • capture 옵션

    __이면 핸들러는 __ 단계에서 동작.

    • false → 버블링
    • true → 캡처링
  • 이벤트가 실제 타깃 요소에 전달되는 단계인 ‘타깃 단계’(두 번째 단계)는 별도로 처리되지 x.

    캡처링과 버블링 단계의 핸들러는 타깃 단계에서 트리거 됨.

📌 예시 (캡처링과 버블링)

문서 내 요소 '전체’에 핸들러를 할당해서 어떤 핸들러가 동작하는지

<p> 클릭 시, 이벤트 전달 순서

  1. HTML → BODY → FORM → DIV (캡처링 단계, 첫 번째 리스너)

  2. P (타깃 단계, 캡쳐링과 버블링 둘 다에 리스너를 설정했기 때문에 두 번 호출됩니다.)

  3. DIV → FORM → BODY → HTML (버블링 단계, 두 번째 리스너)

📌 참고

  • event.eventPhase

    현재 발생 중인 이벤트 흐름의 단계 파악 가능

    • 방법

      반환되는 정숫값에 따라 이벤트 흐름의 현재 실행 단계를 구분

    • 이 프로퍼티는 자주 사용 되지 x.

      이유: 핸들러를 통해 흐름 단계 파악 가능

  • 핸들러를 제거 시, removeEventListener가 같은 단계에 있어야 함.

    addEventListener(..., true)로 핸들러를 할당해 줬다면, 핸들러를 지울 때, removeEventListener(..., true)를 사용해 지워야 함.

    같은 단계에 있어야 핸들러가 지워집니다.

  • 같은 요소와 같은 단계에 설정한 리스너는 설정한 순서대로 동작

    특정 요소에 addEventListener를 사용해 한 단계에 이벤트 핸들러를 여러 개 설정했다면 이 핸들러들은 설정한 순서대로 동작

    elem.addEventListener("click", e => alert(1)); // 첫 번째로 트리거됨.
    elem.addEventListener("click", e => alert(2));
  • e.preventDefault()


참고

profile
복습 목적 블로그 입니다.

0개의 댓글