CS/프로그래밍

이벤트 버블링

Haegnim 2023. 7. 16. 17:59

아래의 글은 좋은 글들을 발췌해 모아 편집한 내용입니다.

발췌의 출처는 제일 하단에 모아놓았습니다.

브라우저 이벤트

이벤트란 시스템에서 일어나는 액션이다. 브라우저의 모든 DOM 노드는 액션을 만들어 낼 수 있다.

이벤트 흐름의 3단계

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

 


참고) 자주 사용되는 DOM 이벤트

마우스 이벤트:

  • click : 요소 위에서 마우스 왼쪽 버튼을 눌렀을 때(터치스크린이 있는 장치에선 탭 했을 때) 발생합니다.
  • contextmenu –:요소 위에서 마우스 오른쪽 버튼을 눌렀을 때 발생합니다.
  • mouseover와 mouseout : 마우스 커서를 요소 위로 움직였을 때, 커서가 요소 밖으로 움직였을 때 발생합니다.
  • mousedown과 mouseup : 요소 위에서 마우스 왼쪽 버튼을 누르고 있을 때, 마우스 버튼을 뗄 때 발생합니다.
  • mousemove : 마우스를 움직일 때 발생합니다.

폼 요소 이벤트:

  • submit : 사용자가 <form>을 제출할 때 발생합니다.
  • focus : 사용자가 <input>과 같은 요소에 포커스 할 때 발생합니다.

키보드 이벤트:

  • keydown과 keyup : 사용자가 키보드 버튼을 누르거나 뗄 때 발생합니다.

문서 이벤트:

  • DOMContentLoaded : HTML이 전부 로드 및 처리되어 DOM 생성이 완료되었을 때 발생합니다.

CSS 이벤트:

  • transitionend : CSS 애니메이션이 종료되었을 때 발생합니다.

 


이벤트 버블링

한 요소에 이벤트가 발생하면, 요소에 할당된 이벤트가 동작하고 해당 요소의 최상위 부모까지 이벤트가 전달되어지는 과정이다.
거의 모든 이벤트는 버블링 된다.(focus 이벤트 등등, 버블링 되지 않는 이벤트도 존재한다.)

아래의 예제 코드에서 p를 클릭하면 alert p -> div -> form 순으로 이벤트가 발생한다.

<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>

이벤트 타겟

부모 요소의 handler는 이벤트가 어디서 발생하는 지 정보를 얻을 수 있다.
이벤트가 발생한 가장 안쪽의 요소는 타겟(target) 요소라고 부른다.
event.target을 사용해 접근할 수 있다.

event.target과 this(event.currentTarget)의 차이점

이벤트 타겟 : 실제 이벤트가 시작된 타겟 요소. 버블링이 진행되도 변하지 않는다.
this는 현재 요소로 현재 실행중인 핸들러가 할당된 요소를 참조한다.

이벤트 캡처링


이벤트 버블링과 반대 방향으로 진행되는 이벤트 전파 방식이다. 최상위 요소에서 시작해 아래로 전파된다.

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

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

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);
}

event.stopPropagation()

이벤트가 전파되는 것을 막는 api

이벤트 버블링으로 하위요소의 이벤트가 상위요소로 퍼지는 걸 막기 위해 사용할 수 있다.
버튼을 클릭해도 body의 onClick 이벤트가 발생하지 않는다.

<body onclick="alert(`버블링은 여기까지 도달하지 못합니다.`)">
	<button onclick="event.stopPropagation()">
		버튼
	</button>
</body>

event.stopPropagation() 문제사항 시나리오

이벤트 버블링을 막아야 하는 경우는 거의 없다. 핸들러의 event 객체에 데이털르 저장해 다른 핸들러에서 읽을 수 있게 하면, 아래쪽에서 무슨 일이 일어나는지를 부모 요소의 핸들러에게 전달할 수 있다. 이 방법으로도 이벤트 버블링을 통제할 수 있다.

event.stopPropagation() 문제사항 시나리오
step1️⃣
중첩 메뉴를 만들었다. 각 서브 메뉴에 해당하는 요소에서 클릭 이벤트를 처리하도록 하고, 상위 메뉴의 클릭 이벤트 핸들러는 동작하지 않도록 stopPropagation을 적용한다.
step2️⃣
사람들이 페이지에서 어디를 클릭했는지 등의 행동 패턴을 분석하기 위해, window내에서 발생하는 클릭 이벤트 전부를 감지한다. 이런 분석 시스템의 코드는 클릭 이벤트를 감지하기 위해 document.addEventListener('click',)을 사용한다.
step3️⃣
stopPropagation을 사용한 영역은 '죽은 영역(dead zone)'이 되어버린다. stopPropagation로 버블링을 막아놓은 영역에선 분석 시스템의 코드가 동작하지 않기 때문에, 분석이 제대로 되지 않는다.

 


이벤트 위임

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

이벤트 위임의 장점

  • 많은 핸들러를 할당하지 않아도 되기 때문에 초기화가 단순해지고 메모리가 절약된다.
  • 요소를 추가하거나 제거할 때 해당 요소에 할당된 핸들러를 추가하거나 제거할 필요가 없기 때문에 코드가 짧아진다.
  • innerHTML이나 유사한 기능을 하는 스크립트로 요소 덩어리를 더하거나 뺄 수 있기 때문에 DOM 수정이 쉬워진다.
  • 이벤트 위임의 단점
  • 이벤트 위임을 사용하려면 이벤트가 반드시 버블링 되어야 한다. (몇몇 이벤트는 버블링 되지 않음을 상기할 것)
  • 낮은 레벨에 할당한 핸들러엔 event.stopPropagation()를 쓸 수 없다.
  • 컨테이너 수준에 할당된 핸들러가 응답할 필요가 있는 이벤트이든 아니든 상관없이 모든 하위 컨테이너에서 발생하는 이벤트에 응답해야 하므로 CPU 작업 부하가 늘어날 수 있다. (이런 부하는 무시할만한 수준이므로 실제로는 잘 고려하지 않는다.)

 

이벤트 위임 알고리즘

  1. 컨테이너에 하나의 핸들러를 할당한다.
  2. 핸들러의 event.target을 사용해 이벤트가 발생한 요소가 어디인지 알아낸다.
  3. 원하는 요소에서 이벤트가 발생했다고 확인되면 이벤트를 핸들링한다.

참고자료

버블링과 캡처링

이벤트 버블링, 이벤트 캡처 그리고 이벤트 위임까지

이벤트 위임

'CS > 프로그래밍' 카테고리의 다른 글

ESLint  (0) 2023.07.23
이벤트 루프  (0) 2023.07.23
클로저  (2) 2023.07.16
MVC, MVP, MVVM 모델  (0) 2023.07.09
await, async  (0) 2023.07.02