이벤트 버블링과 캡처링

23094 단어 JavaScriptJavaScript

이벤트 버블링(Event Bubbling) 이란?

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

조금 더 이해하기 쉽게 설명하자면, 특정 화면 요소에 이벤트가 발생했을 때, 해당 요소에 할당된 이벤트 핸들러가 작동하고, 이어서 부모 요소에 할당된 핸들러가 동작하며, 가장 최상단의 화면 요소인 document(body) 를 만날 때 까지 이 과정이 반복된다.

예제 코드

const divClickHandler = () => {
	console.log('clicked div');
};

const aClickHandler = () => {
	console.log('clicked a');
}

const buttonClickHandler = () => {
	console.log('clicked button');
}

// Vanilla Javascript에서 이벤트 리스너/핸들러를 등록하는 방법
const divEl = document.querySelector('div');
divEl.addEventListener('click', divClickHandler);

const aEl = document.querySelector('a');
aEl.addEventListener('click', aClickHandler);

const buttonEl = document.querySelector('button');
buttonEl.addEventListener('click', buttonClickHandler);

// React에서 이벤트 리스너/핸들러를 등록하는 방법
<div onClick={divClickHandler}>
	<a onClick={aClickHandler}>
		<button onClick={buttonClickHandler}>Button</button>
	</a>
</div>

// button 클릭 시 결과
// clicked button
// clicked a
// clicked div

이벤트 캡쳐링(Event Capturing) 이란?

이벤트 캡쳐링은 이벤트 버블링과 반대 방향으로 진행되는 이벤트 전파 방식이다.

이벤트 버블링이 특정 화면 요소의 이벤트가 발생했을 때, 가장 최상위의 화면 요소까지 순차적으로 이벤트 핸들러를 작동시킨다고 하면, 이벤트 캡쳐링은 반대로 가장 최상위의 화면 요소 핸들러를 먼저 작동시키고, 특정 화면 요소 핸들러를 마지막에 작동 시킨다.

예제 코드

Vanilla Javascript에서 이벤트 캡쳐링은 이벤트 리스너를 등록할 때, addEventListener() API에서 옵션으로 설정할 수 있다.

React에서 이벤트 캡쳐링은 이벤트 리스너를 등록할 때 이벤트명 뒤에 Capture를 붙여 설정할 수 있다.

💡 `addEventListener()`를 통해 이벤트 리스너, 핸들러를 등록했다면, 반드시 `removeEventListener()`를 통해 리스너, 핸들러를 지워주어야 한다.

ex) removeEventListener(’click’, buttonClickHandler, { capture: true });

const divClickHandler = () => {
	console.log('clicked div');
};

const aClickHandler = () => {
	console.log('clicked a');
}

const buttonClickHandler = () => {
	console.log('clicked button');
}

// Vanilla Javascript에서 이벤트 캡쳐링을 사용하는 방법
const divEl = document.querySelector('div');
divEl.addEventListener('click', divClickHandler, { capture: true });

const aEl = document.querySelector('a');
aEl.addEventListener('click', aClickHandler, { capture: true }); 

const buttonEl = document.querySelector('button');
buttonEl.addEventListener('click', buttonClickHandler, true); // boolean으로 넘겨도 된다.

// React에서 이벤트 캡쳐링을 사용하는 방법
<div onClickCapture={divClickHandler}>
	<a onClickCapture={aClickHandler}>
		<button onClickCapture={buttonClickHandler}>Button</button>
	</a>
</div>

// button 클릭 시 결과
// clicked div
// clicked a
// clicked button

이벤트 흐름도

표준 DOM 이벤트에서 정의한 이벤트 흐름은 다음과 같다.

  1. 캡쳐링 단계 (Capture Phase) - 이벤트가 하위 요소로 전파되는 단계.
  2. 타깃 단계 (Target Phase) - 이벤트가 실제 타깃 요소에 전달되는 단계.
  3. 버블링 단계 (Bubbling Phase) - 이벤트가 상위 요소로 전파되는 단계.

위의 이벤트 흐름을 이해했다면, 다음 코드가 어떻게 작동하는지 예상 될 것이다.

  1. <a> 에서는 이벤트 캡쳐링을 사용하므로 <a> 의 핸들러가 가장 먼저 작동한다.
  2. <button><div>는 이벤트 캡쳐링을 사용하지 않으므로, 버블링 단계에서 핸들러가 작동한다.
  3. 따라서 <a> 핸들러 작동 이후, <button> 핸들러와 <div> 핸들러가 순서대로 작동한다.
const divClickHandler = () => {
	console.log('clicked div');
};

const aClickHandler = () => {
	console.log('clicked a');
}

const buttonClickHandler = () => {
	console.log('clicked button');
}

<div onClick={divClickHandler}>
	<a onClickCapture={aClickHandler}>
		<button onClick={buttonClickHandler}>Button</button>
	</a>
</div>

// button 클릭 시 결과
// clicked a
// clicked button
// clicked div

버블링 중단하기 (e.stopPropagation())

이벤트 핸들러에서 인자로 받은 Event 객체를 이용하여, 이벤트 버블링을 중단시킬 수 있다.

e.stopPropagation()을 사용하여 버블링을 중단시키며, 상위 요소의 핸들러를 실행시키지 않는다.

const divClickHandler = () => {
	console.log('clicked div');
};

const aClickHandler = () => {
	console.log('clicked a');
}

const buttonClickHandler = (e) => {
	e.stopPropagation();
	console.log('clicked button');
}

<div onClick={divClickHandler}>
	<a onClick={aClickHandler}>
		<button onClick={buttonClickHandler}>Button</button>
	</a>
</div>

// button 클릭 시 결과
// clicked button

버블링 중단하기2 (e.stopImmediatePropagation())

만약, 한 요소의 특정 이벤트를 처리하는 핸들러가 여러개일 경우, e.stopPropagation()으로 버블링을 멈추더라도, 다른 핸들러는 그대로 작동한다.
다른 핸들러의 작동도 멈추기 위해서는 e.stopImmediatePropagation()을 사용해야 한다.

단, 핸들러를 등록한 순서와 e.stopImmediatePropagation() 를 호출하는 순서에 유의한다.

좋은 웹페이지 즐겨찾기