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

Bonggus·2021년 10월 12일
0

브라우저공부

목록 보기
3/9
post-thumbnail
post-custom-banner

브라우저에서 어떻게 특정 화면 요소의 이벤트를 감지하는지, 그리고 그 이벤트를 어떻게 다른 화면 요소에 전파하는지 알아보자

이벤트 등록

이벤트 등록은 웹 애플리케이션에서 사용자의 입력을 받기 위해 필요한 기능이다.

이벤트 리스너는 항상 대기중이며, 해당 이벤트가 발생하면 등록했던 이벤트가 실행된다. 모든 DOM들이 이벤트 리스너를 등록할 수 있는 속성을 가지고 있다.

<button>add one item</button>
const button = document.querySelector('button');
button.addEventListener('click', addItem);

function addItem(event) {
	console.log(event);
}

add one item을 클릭하면 addItem함수가 실행된다. addItem함수에 event인자가 넘어오는데, 콘솔에 출력해보면 이벤트와 관련된 정보를 확인할 수 있다.

addEventListener() 웹API는 웹 개발자들이 화면에 동적인 기능을 추가하기 위해 자연스럽게 접하게되는 기본 기능이다. 사용자의 입력에 따라 추가적인 동작을 구현할 수 있다.

그렇다면 여기서, 브라우저는 어떻게 이벤트의 발생을 감지할까? 브라우저가 이벤트를 감지하는 방법에는 2가지가 있다.

이벤트 버블링(bubbling)

이벤트 버블링은 특정 화면 요소에서 이벤트가 발생했을 때 해당 이벤트가 더 상위의 화면 요소들로 전달되어 가는 특성을 의미한다.

버블링이란 자식의 이벤트가 부모에도 전달되는 것

HTML 요소는 기본적으로 트리 구조를 갖는다. 트리 구조상으로 한 단계 위에있는 요소를 상위로소라고 한다.

<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 class="three"></div>를 클릭하면 아래와 같은 결과가 나온다.

이렇게 3개가 찍히는 이유는 브라우저가 이벤트를 감지하는 방식 때문이다. 브라우저는 특정 화면 요소에서 이벤트가 발생했을 때 그 이벤트를 최상위에 있는 화면 요소까지 이벤트를 전파시킨다. 따라서 three -> two -> one 순서대로 div 태그에 등록된 이벤트들이 실행된다. two를 클릭하면 two -> one 순으로 클릭 이벤트가 동작한다.

주의할 점은 각 태그마다 이벤트가 등록되어 있기 때문에 상위 요소로 이벤트가 전달되는 것을 확인할 수 있다는 것이다. 만약 이벤트가 특정 div태그에만 있다면 위와 같은 동작결과는 확인할 수 없다.
이와 같이 하위에서 상위 요소로 이벤트가 전파되는 방식을 이벤트 버블링이라고 한다. Trigger clicks all the way up

이벤트 캡쳐링(capturing)

이벤트 캡쳐링은 이벤트 버블링과 반대 방향으로 진행되는 이벤트 전파 방식이다. 특정 이벤트가 발생했을 때 최상위 요소에서 해당 태그를 찾아서 내려간다.

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

이벤트 캡쳐링은 addEventListener() API에서 옵션 객체에 captrue: true를 설정해면 된다.

버블링과 같은 방식으로 테스트를 해보면, 가장 안쪽에있는 <div class="three"></div>를 클릭하면 결과는 아래처럼 나타난다. (버블링과 반대)

event.stopPropagation()

그렇다면 이렇게 이벤트가 전달되는 방식말고 원하는 화면 요소의 이벤트만 신경쓰고 싶으면 어떻게 해야할까? 그 답이 stopPropagation함수이다.

이 API는 해당 이벤트가 전파되는 것을 막는다. 따라서 버블링의 경우 클릭한 요소의 이벤트만 발생시키고 상위 요소로 이벤트가 전달되는 것을 막아준다. 캡처링의 경우 클릭한 요소의 최상상위 요소의 이벤트만 동작시키고 하위 요소들로 이벤트를 전달하지 않는다.

stopPropagation 메소드는 태그를 클릭 시 부모에게 이벤트가 전달(버블링)되지 않도록 한다.

버블링의 경우 클릭된 대상만 출력이되고, 캡처링의 경우 최상위 요소만 출력된다.

버블링

캡처링

이벤트 위임

이벤트 위임은 실제 바닐라JS로 웹 앱을 구현할 때 자주 사용하게 되는 코딩패턴이다.

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

말 그대로 이벤트 핸들러를 다른(상위 태그)에 위임하는 행위이다.

자바스크립트의 querySelectorAll()를 이용해 화면에 존재하는 모든 인풋 박스 요소를 가져와서, 각 인풋 박스의 요소에 클릭 이벤트 리스너를 추가한다. 체크버튼을 클릭하면 위와같은 alert창이 뜬다.

만약 여기에 새로운 리스트를 추가하게되면 어떻게될까?

새로 추가된 리스트 아이템에는 이벤트 리스너가 동작하지 않는다. 그 이유는 이벤트를 추가하는 시점에 새로 추가된 리스트는 클릭 이벤트가 등록되지 않았기 때문이다.

하지만, 매번 리스트가 생길때마다 이벤트리스너를 넣어주는 작업은 번거롭다. 이 번거로운 작업을 해결할 수 있는 방법이 이벤트 위임이다.

코드를 아래와 같이 변경하면

var itemList = document.querySelector('.itemList');
itemList.addEventListener('click', function(event) {
	alert('clicked');
});

리스트에 이벤트를 걸어주는 것이 아니라 상위 요소인 ul태그에 이벤트 리스너를 달아놓으면 하위에서 발생한 클릭 이벤트를 감지한다 (버블링)

출처

profile
프론트엔드
post-custom-banner

0개의 댓글