이벤트 위임, 버블링, 캡처링

Sheryl Yun·2022년 2월 25일
0

이벤트 버블링

특정 위치에서 발생한 이벤트가 최상위 요소까지 올라가며 연속으로 발생하는 현상을 의미한다.

코드 예

<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(e) {
	console.log(e.currentTarget.className);
}

세 개의 div 태그에 모두 클릭 이벤트를 등록하고 클릭 시 logEvent 함수를 실행하는 코드이다.
최하위 요소인 <div class="three"></div>를 클릭하면 콘솔에 다음처럼 찍힌다.

three div 하나밖에 클릭하지 않았는데도 위의 부모요소에 등록된 클릭 이벤트들이 전부 실행되었다.
이때 주의할 점은 클릭한 곳으로부터 상위로 올라간다는 것이다.

이렇게 이벤트 버블링이 발생하게 되는 이유는 두 가지이다.

👆 브라우저가 기본적으로, 특정 요소에서 이벤트가 발생했을 때 그 이벤트를 최상위에 있는 요소까지 전파시키는 이벤트 버블링적 속성을 갖고 있어서이다.
(* 이벤트 캡처링의 경우 이벤트 리스너의 옵션을 바꿔줘야 발생한다)

✌ div 태그들이 모두 부모-자식 관계이고, 각 div에 모두 이벤트가 등록되어 있어서이다.
(만약 이벤트가 특정 div 에만 달려 있다면 이벤트 버블링이 발생하지 않는다)

이벤트 캡처링

이벤트 버블링과 반대로, 이벤트 발생 시 최상단 요소에서 이벤트가 발생한 위치까지 내려가며 연속으로 이벤트가 발생하는 현상이다.

코드 예

<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, {
		capture: true // default 값은 false
	});
});

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

이벤트 캡처링은 브라우저의 기본적 속성이 아니기 때문에 이벤트 리스너의 옵션에 capture: true를 설정해줘야 발생한다.
그리고 아까처럼 <div class="three"></div> 를 클릭하면 콘솔에는 다음과 같이 나타난다.

이벤트 버블링과 달리, three를 눌렀음에도 최상단인 one 부터 실행되는 것을 볼 수 있다. (two를 누르면 one부터 시작해서 two까지 찍힌다)
어디를 눌러도 무조건 최상단의 이벤트부터 시작되어 누른 데까지 실행된다는 걸 알 수 있다.

해결

이벤트 버블링과 캡처링 현상이 발생하지 않게 하려면
이벤트 발생 시 실행되는 함수의 첫 줄에 e.stopPropagation()을 넣어주면 된다.

function logEvent(e) {
	e.stopPropagation();
}

stopPropagation()은 이벤트가 전파되는 것을 막아주는 웹 API이다.
이 코드를 쓰면 아래로든 위로든 이벤트가 퍼져나가지 않고
이벤트 발생 시 무조건 첫번째 발생한 이벤트만 실행한다.
(위의 예제에서는 버블링의 경우 three만 출력, 캡처링의 경우 one만 출력)

이벤트 위임

이벤트 버블링과 캡쳐링은 이벤트 위임을 위한 선수 지식에 가깝다.

이벤트 위임은 자바스크립트로 코드를 작성할 때 자주 쓰게 되는 개념이다.

정의를 하자면 ‘하위 요소 각각에 이벤트를 붙이지 않고 상위 요소에만 이벤트를 등록하여 하위 요소까지 퍼져나가게 하는 방식'이다.

코드 예

다음과 같이 할 일 checkbox에 체크하는 코드가 있다.

<h1>오늘의 할 일</h1>
<ul class="itemList">
	<li>
		<input type="checkbox" id="item1">
		<label for="item1">이벤트 버블링 학습</label>
	</li>
	<li>
		<input type="checkbox" id="item2">
		<label for="item2">이벤트 캡쳐 학습</label>
	</li>
</ul>

querySelectorAll을 통해 체크박스 인풋 하나하나에 클릭 이벤트를 달아주면
인풋 박스가 추가될 때마다 매번 이벤트를 달아줘야 한다.

var inputs = document.querySelectorAll('input');

inputs.forEach(function(input) {
	input.addEventListener('click', function(event) {
		alert('clicked');
	});
});

하지만 이벤트 위임을 활용하여 인풋 박스의 상위 요소인 ul 태그 하나에만 이벤트 리스너를 달아주면 이벤트 버블링 현상이 발생하여
하위의 인풋 박스 중 어느 것을 눌러도 상단의 ul 태그까지 클릭 이벤트가 버블링되어 올라가면서 상단 ul의 이벤트 리스너가 하위의 이벤트를 감지할 수 있게 된다.

var itemList = document.querySelector('.itemList');

itemList.addEventListener('click', function(event) {
	alert('clicked');
});

이제 리스트 아이템을 새로 추가할 때마다 클릭 이벤트를 매번 안 달아도 된다 🧚‍♀️


출처: 캡틴판교님 github.io 게시글

profile
데이터 분석가 준비 중입니다 (티스토리에 기록: https://cherylog.tistory.com/)

0개의 댓글