본문 바로가기
이론/Frontend

자바스크립트의 이벤트 버블링 (JS eventBubbling)

by 유세지 2020. 9. 17.

자바스크립트에 대해서 아무것도 모르고 코딩을 할때 (물론 지금도 전혀 모르지만), 한 요소에 이벤트를 주기만 하면 원인 모를 오작동이 있었습니다. 분명히 특정한 요소 하나에 클릭 이벤트를 주었는데 그 요소를 누르면 요소를 감싸고 있던 상위 요소의 이벤트까지 같이 발생해버리는 현상이었습니다.

 

그땐 보면서도 이게 왜 이러나... 싶었지만 이제서야 그 이유를 알게되어서 정리해봅니다.

 

먼저 상황을 되짚어 보기 위해 문제가 되었던 구조를 간단히 재현해보겠습니다.

 

<!DOCTYPE html>
<html>
	<head>
		<link rel="stylesheet" href="style.css">
	</head>
	<body>
		<div id = "test">
			<button id = "btn">
				이벤트 작동
			</button>
		</div>
	</body>
	<script>
		
		let test = document.getElementById('test');
		let btn = document.getElementById('btn');
		
		test.addEventListener('click', clicked);
		btn.addEventListener('click', clicked);
		
		function clicked(e) {
			console.log(this.id);
		}
	</script>
</html>

 

 

test라는 id를 가진 div 아래에 btn 이라는 id를 가진 버튼이 있는 구조입니다.

요소를 클릭하게 되면 그 요소의 id값을 콘솔로 출력해주어 어떤 이벤트가 실행되었는지 확인할 수 있습니다.

 

 

버튼을 클릭해보니 btn의 이벤트가 먼저 실행되고, 바로 이어서 test의 이벤트가 실행된 것을 알 수 있습니다. 이렇게 자식 요소의 이벤트 실행을 의도하였던 것인데 부모 요소의 이벤트까지 실행시켜버리면 난감한 일이 아닐 수 없습니다.

 

지금처럼 자식 요소의 이벤트가 부모 요소로 전달되는 특성을 이벤트 버블링 (Event Bubbling) 이라고 합니다. 물속에서 공기 방울(bubble)들이 위로 올라가는 이미지를 생각하시면 될 것 같습니다.

 

이러한 버블링 현상을 방지하기 위해서는 이벤트 단에 이벤트 전파를 방지하는 코드를 추가해줍니다.

 

stopPropagation();

 

btn에 걸린 이벤트만 실행됩니다.

 

 

stopPropagation()을 이벤트 함수 안에 추가 해주는 것으로 이벤트 전파가 일어나지 않고, btn에 적용된 클릭 이벤트만 일어나는 것을 확인할 수 있었습니다.

 

여기에 추가로 한가지 더, 이벤트 버블링과 유사한 현상으로 이벤트 캡처링(Event Capturing)이 있습니다.

버블링과의 차이점은 이벤트의 전파 방향인데, 버블링이 하위 요소부터 상위 요소로 퍼지는 Bottom-up 방식을 가지고 있다면 캡처링은 반대로 상위 요소부터 하위 요소로 퍼지는 Top-down 방식을 가지고 있습니다.

 

캡처링과 버블링은 오류가 아니라 엄연한 기능이기 때문에, 이벤트를 등록할때 어떤 방식을 사용할지 설정할 수 있습니다.

 

addEventListener 문서, 출처 MDN web docs

 

addEventListener의 구문을 보시면 type과 listener 말고도 optionsuseCapture, wantsUntrusted 등 다양한 매개변수가 더 있는 것을 알 수 있습니다. 이 중 wantsUntrusted는 리스너를 시스템 그룹에 추가할지 묻는 불리언 타입의 매개 변수인데 실행되는 브라우저 환경이 정해져있는 비표준이기에 주의가 필요합니다.

 

useCapture의 자세한 설명

 

useCapture의 매개변수는 true와 false를 받는 Boolean 타입입니다. 기본값은 false로, 이벤트의 내용을 상위 리스너에게 전달하는 이벤트 버블링이 적용됩니다. 만약 true를 전달해준다면 하위 리스너에게 이벤트를 전달하는 이벤트 캡처링이 적용됩니다.

 

버블링이 아닌 캡처링은 이런식으로 적용할 수 있습니다.

 

target.addEventListener('click', clicked, true);

 

오늘 포스팅으로 1년만에 궁금증이 해결되었습니다. 덕분에 마음도 시원하네요 :)

모두 즐거운 코딩 되시길 바랍니다!

반응형

댓글