JavaScript - Event Bubbling / Capturing

DW J·2022년 9월 6일
0

develop_wis

목록 보기
7/9

사용자의 액션에 의해 다이나믹한 화면을 구성함에 있어 Javascript의 이벤트는 가장 중요한 키워드가 아닐까 싶습니다. 이벤트에서 버블링(Bubbling)과 캡쳐링(Capturing)이 무엇이고 어떻게 동작하는지 알아보겠습니다

표준 DOM 이벤트에서 정의한 3가지 이벤트 흐름
1. Capturing 단계 - 이벤트가 하위 요소로 전파되는 단계
2. Target 단계 - 이벤트가 실제 타깃 요소로 전달되는 단계
3. Bubbling 단계 - 이벤트가 상위 요소로 전파되는 단계

1. Bubbling

Bubbling 이란?

  • 최상단의 요소까지 전파되는 이벤트 흐름
  • 한 요소에 이벤트가 발생하면, 해당 요소에 등록한 핸들러가 동작하고, 부모 요소의 핸들러가 동작
  • 가장 최상단의 조상 요소를 만날때까지 이 과정이 반복되면서 요소 각각에 할당 된 핸들러가 동작

예시코드)

<div onclick="alert('div')"> // div
	<form onclick="alert('form')"> // form
    	<button onclick="alert('button')"> // button
        	button
        </button>
    </div>
</div>

button을 클릭했을 때 다음과 같은 일이 발생

  1. button에 할당 된 onclick이벤트 실행 > button
  2. button의 부모인 form에 할당 된 onclick이벤트 실행 > form
  3. form의 부모인 div에 할당 된 onclick이벤트 실행 > div
  4. document객체를 만날 때 까지 각 요소에 등록 된 이벤트 핸들러가 동작

위와 같은 흐름을 이벤트 버블링(Bubbling)이라고 함
Javascript에서 동작하는 거의 모든 이벤트에서는 버블링이 일어남 - focus, blur등 몇몇 이벤트 제외

event.target

부모 요소의 핸들러는 이벤트가 정확하게 어디서 발생되었는지에 대한 정보를 얻을 수 있다 이벤트가 발생한 가장 안쪽의 요소는 타킷(target) 요소 라고 하며, event.target을 사용하여 접근할 수 있다.

target vs currentTarget

  • target은 실제 이벤트가 시작 된 target요소 버블링이 진행되어도 변하지 않음
  • currentTarget은 현재 요소로 실행 중인 핸들러가 할당 된 요소를 참조함
<div onclick="alert('div')"> // div
	<form> // form
    	<button> // button
        	button
        </button>
    </div>
</div>

각 요소를 클릭했을 때 target과 currentTarget

  • button 클릭 > target : button / currentTarget : div
  • form 클릭 > target : form / currentTarget : div
  • div 클릭 > target : div / currentTarget : div

핸들러는 div(최상단)에 있지만 핸들러에서 div 안의 모든 요소에서 발생하는 클릭 이벤트를 catch하고 있기때문에, 이벤트가 어디서 발생하든 div까지 이벤트가 버블링 되어 핸들러를 실행시킴

버블링 중단

<div onclick="alert('이벤트가 여기까지 도달하지 못함')">
	<button onclick="event.stopPropagation()">클릭!!</button>
</div>

이벤트 객체 메서드인 stopPropagation()을 사용하면 버블링을 중단 할 수 있음

이벤트 객체 메서드 더 보기

2. Capturing

Capturing 이란?

  • 최하단 요소까지 전파되는 이벤트 흐름
  • Capturing을 사용하는 경우는 흔하지 않음 (Bubbling)사용
  • Capturing단계에서 이벤트를 catch하려면 addEventListener의 capture옵션을 true로 설정해야함
element.addEventListener('', { capturing: true });
element.addEventListener('', true);

addEventListener의 두번째 인자로 코드와 같이 넣어주면 Capturing을 catch할 수 있음
두번째 인자의 default는 false이고 bubbling이 동작

공식적인 이벤트 흐름은 3단계지만 이벤트가 실제 타깃 요소에 전달되는 단계인 타깃 단계는 별도로 처리되지 않음 Capturing과 Bubbling단계의 핸들러는 타깃 단계에서 트리거됨

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

문서 내 요소 전체에 대한 핸들러가 동작하는 방법

P를 클릭했을 때 이벤트 흐름
1. HTML > BODY > FORM > DIV (Capturing 단계)
2. P (Target 단계 / Capturing과 Bubbling에서 리스너를 설정했기 때문에 두번 호출)
3. DIV > FORM > BODY > HTML (Bubbling 단계)

핸들러를 제거할 때도 addEventListener에 설정한 값 그대로 removeEventListener에 설정해야 핸들러가 정상적으로 제거 됨
ex)
addEventListener(..., true) > removeEventListener(..., true)


참고

profile
잘하는것보다 꾸준히하는게 더 중요하다

0개의 댓글