[개념] 이벤트 버블링, 이벤트 캡쳐링

posinity·2023년 3월 11일
0

JavaScript

목록 보기
24/31

자식 요소에서 발생한 이벤트가 부모 요소로 전파되는 것을 버블링이라 하고, 부모 요소부터 시작하여 이벤트를 발생시킨 자식 요소까지 도달하는 것을 캡처링이라 한다. 주의할 것은 버블링과 캡처링은 둘 중에 하나만 발생하는 것이 아니라 캡처링부터 시작하여 버블링으로 종료한다는 것이다.

이벤트 버블링

한 요소에 이벤트가 발생하면, 이 요소에 할당된 핸들러가 동작하고, 이어서 부모 요소의 핸들러가 동작합니다. 가장 최상단의 조상 요소를 만날 때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작합니다.

3개의 요소가 FORM > DIV > P 형태로 중첩된 구조를 살펴봅시다. 요소 각각에 핸들러가 할당되어 있습니다.

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

가장 안쪽의 <p>를 클릭하면 순서대로 다음과 같은 일이 벌어집니다.

<p>에 할당된 onclick 핸들러가 동작합니다.
바깥의 <div>에 할당된 핸들러가 동작합니다.
그 바깥의 <form>에 할당된 핸들러가 동작합니다.
document 객체를 만날 때까지, 각 요소에 할당된 onclick 핸들러가 동작합니다.

이런 동작 방식 때문에

요소를 클릭하면 p → div → form 순서로 3개의 얼럿 창이 뜨는것이죠.

이런 흐름을 '이벤트 버블링’이라고 부릅니다. 이벤트가 제일 깊은 곳에 있는 요소에서 시작해 부모 요소를 거슬러 올라가며 발생하는 모양이 마치 물속 거품(bubble)과 닮았기 때문입니다.

버블링 추가설명

세 개의 div 태그가 있고 가장 아래에 있는 div 태그에서 이벤트가 발생했을 때 최상위 요소인 body 태그까지 이벤트가 전달되는 모습을 나타내었습니다. 그럼 이제 같이 코드를 보겠습니다.

<body>
	<div class="one">
		<div class="two">
			<div class="three">
			</div>
		</div>
	</div>
</body>
var divs = document.querySelectorAll('div');
divs.forEach(function(div) {
	div.addEventListener('click', logEvent);
});

function logEvent(event) {
	console.log(event.currentTarget.className);
}

위 코드는 세 개의 div 태그에 모두 클릭 이벤트를 등록하고 클릭 했을 때 logEvent 함수를 실행시키는 코드입니다. 여기서 위 그림대로 최하위 div 태그

를 클릭하면 아래와 같은 결과가 실행됩니다.

div 태그 한 개만 클릭했을 뿐인데 왜 3개의 이벤트가 발생되는 걸까요? 그 이유는 브라우저가 이벤트를 감지하는 방식 때문입니다.

브라우저는 특정 화면 요소에서 이벤트가 발생했을 때 그 이벤트를 최상위에 있는 화면 요소까지 이벤트를 전파시킵니다. 따라서, 클래스 명 three -> two -> one 순서로 div 태그에 등록된 이벤트들이 실행됩니다. 마찬가지로 two 클래스를 갖는 두 번째 태그를 클릭했다면 two -> one 순으로 클릭 이벤트가 동작하겠죠.

여기서 주의해야 할 점은 각 태그마다 이벤트가 등록되어 있기 때문에 상위 요소로 이벤트가 전달되는 것을 확인할 수 있습니다. 만약 이벤트가 특정 div 태그에만 달려 있다면 위와 같은 동작 결과는 확인할 수 없습니다.

이와 같은 하위에서 상위 요소로의 이벤트 전파 방식을 이벤트 버블링(Event Bubbling)이라고 합니다.

캡쳐링

표준 DOM 이벤트에서 정의한 이벤트 흐름엔 3가지 단계가 있습니다.

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

특정 이벤트가 발생했을 때 최상위 요소인 body 태그에서 해당 태그를 찾아 내려갑니다. 그럼 이벤트 캡쳐는 코드로 어떻게 구현할 수 있을까요?

<body>
	<div class="one">
		<div class="two">
			<div class="three">
			</div>
		</div>
	</div>
</body>
HTMLCopy
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);
}

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

따라서, 아까와 동일하게

를 클릭해도 아래와 같은 결과가 나타납니다.

참고자료

도서 모던 자바스크립트 딥다이브

이벤트 기초-버블링과 캡쳐링

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

profile
문제를 해결하고 가치를 제공합니다

0개의 댓글