본문 바로가기

자바스크립트

이벤트 위임

이벤트 흐름(Event Flow)

타겟 엘리먼트(최초로 이벤트를 발생시킨 엘리먼트)에 이벤트가 일어날 경우 해당 이벤트는 다음 3단계를 거친다.

 

  1. 캡처링 단계 : window부터 타겟 엘리먼트까지 이벤트가 아래로 전달 (디폴트는 실행 X)
  2. 타겟 단계 : 이벤트가 타겟 엘리먼트에 도달 (타깃 단계, 캡쳐링과 버블링 둘 다에 리스너를 설정했기 때문에 두 번 호출됩니다)
  3. 버블링 단계 : 이벤트가 타겟 엘리먼트로부터 부모 엘리먼트들에게로 전달
  • event.target과 event.currentTarget
    event.target : 최초로 이벤트를 발생시킨 엘리먼트
    this (=event.currentTarget) : 현재 이벤트가 발생된 엘리먼트

 

이벤트 버블링(Event Bubbling)

특정 엘리먼트에 이벤트가 발생했을 때 이벤트가 그 엘리먼트의 조상들에게 까지 전달되어 올라가는 현상이다.

 

이벤트 캡처링(Event Capturing)

특정 엘리먼트에 이벤트가 발생했을 때 이벤트가 최상단의 부모 엘리먼트로부터 전달되어 내려오는 현상이다.

디폴트는 false로 별다른 옵션을 설정하지 않으면 캡처링이 일어나지 않고,
addEventListener() 메서드의 세 번째 매개변수로 true를 전달해야 캡처링이 일어난다.

 

이벤트 캡처링, 버블링의 발생 이유

브라우저의 요소들은 모두 부모 요소들로 감싸져있기 때문에, 브라우저는 사용자가 div 쪽 좌표를 눌렀을 때 감싸져있는 html을 클릭을 한 것인지, body를 클릭을 한 것인지, div를 클릭 한 것인지 알 수 없다. 즉, 브라우저가 이벤트 발생 의도를 알지 못하기 때문에 캡처링, 버블링이 발생하는 것이다.

그래서 브라우저는 일단 최상위 엘리먼트인 widndow 객체부터 타겟 엘리먼트에 도달할때까지 안쪽으로 들어가면서, 캡처링이 true인 이벤트 리스너가 있다면 이벤트를 실행시킨다. 이것이 이벤트 캡처링 단계이다.

타겟 엘리먼트에 도달했다면 다시 바깥쪽으로 나가면서, 이벤트 리스너가 있다면 이벤트를 실행시킨다. 이것이 이벤트 버블링 단계이다.

 

이벤트 전파 방지

버블링에서는 타겟 엘리먼트에만 이벤트가 발생하도록 해주고, 캡쳐링에서는 타겟 엘리먼트 기준으로 최상단 엘리먼트에만 이벤트가 발생하도록 해준다.

  • event.preventDefault()
    현재 이벤트의 기본 동작을 중단한다.
  • event.stopPropagation()
    현재 이벤트가 상위로 전파되지 않도록 중단한다. 타겟 엘리먼트에 이벤트가 두개 있다면 두 번 반응
  • event.stopImmediatePropagation()
    현재 이벤트가 상위뿐 아니라 현재 레벨에 걸린 다른 이벤트도 동작하지 않도록 중단한다. 타겟 엘리먼트에 이벤트가 두개 있어도 한 번 반응

 

이벤트 위임 (Event Delegation)

이벤트 발생 시 이벤트는 버블링 되어 부모 엘리먼트까지 올라간다. 이를 활용해 이벤트 위임을 사용할 수 있다. 이벤트 위임이란 각각의 요소마다 이벤트 핸들러를 할당하지 않고, 공통되는 부모 요소에만 이벤트 핸들러를 할당하고 이벤트를 관리하는 방식이다.

 

이벤트 위임 장점

이벤트 위임을 적용하면 메모리 사용량이 감소하고 코드가 간결해진다. 왜냐하면 공통되는 상위 요소에서만 addEventListener() 메서드를 호출하면 되므로 이벤트 핸들러 함수가 하나만 필요하고, 상위 요소에서만 getElementById() 메서드를 통해 접근하면 되므로 변수도 하나만 필요해지기 때문이다. (JavaScript에서 함수는 객체이므로 함수가 적어지면 메모리 사용량이 감소한다.)

또한 의도치 않은 동작이 일어나는 것을 방지할 수 있다. 여러 개의 이벤트 리스너를 등록하면 이벤트 버블링에 의해 상위 요소의 이벤트 리스너도 실행되고, 그로 인해 의도하지 않은 결과를 초래할 수도 있다. 이벤트 위임을 적용하면 조건문을 통해 원하는 요소에 원하는 동작을 수행하도록 하여 개발자가 의도한대로 동작하게 된다.

 

<div id="div-content">
  <span id="span-content">
    <button id="btn">버튼</button>
  </span>
</div>

이벤트 위임 적용 전

// 개별 요소를 접근해야함
const divNode = document.getElementById("div-content");
const spanNode = document.getElementById("span-content");
const btnNode = document.getElementById("btn");

// 개별 요소마다 이벤트 리스너를 등록해야함
divNode.addEventListener("click", function () {
  console.log("divNode Click");
});

spanNode.addEventListener("click", function () {
  console.log("spanNode Click");
});

btnNode.addEventListener("click", function () {
  console.log("btnNode Click");
});

이벤트 위임 적용 후

// 상위 요소인 id가 "div-content"인 div 노드만 접근함
const divNode = document.getElementById("div-content");

// div 노드에만 이벤트 리스너를 설정
divNode.addEventListener("click", function (e) {
  const id = e.target.id;
  
  // 이벤트 객체의 target.id로 조건문을 설정
  if (id === "div-content") {
    console.log("div-content id Click");
  } else if (id === "span-content") {
    console.log("span-content id Click");
  } else if (id === "btn") {
    console.log("btn id Click");
  }
});

 

 

이벤트 캡처링과 버블링은 대체 왜 why 일어나는걸까?

[JavaScript] 이벤트 위임

[JS]이벤트 위임(Event Delegation)이란?

[JavaScript] JavaScript에서 이벤트 전파를 중단하는 네가지 방법

 

'자바스크립트' 카테고리의 다른 글

this  (0) 2023.03.17
callback, promise, async/await  (0) 2023.03.14
자바스크립트의 배열  (0) 2023.03.08
Hoisting과 Temporal Dead Zone  (0) 2023.03.06
스코프  (0) 2023.03.03