전 프로젝트에서도 경험했지만, 부모 요소에 클릭 이벤트를 적용하고 자식 요소에도 클릭 이벤트를 적용하면, 부모 요소의 이벤트가 적용되는 문제점이 있었다. 이를 해결하는 방법을 찾아 정리하려고 한다.
`Event.stopPropagation()`
현재 이벤트가 버블링 단계에서 더 이상 전파(propagate)되지 않도록 막아준다.
아래 코드를 실행해보면 자식 요소를 클릭해도 '부모 요소 클릭' 알림창이 뜨는 것을 확인할 수 있다.
<body>
<div class='parent' onclick={() => {alert('부모 요소 클릭')}}>
<div class='child' onclick={() => {alert('자식 요소 클릭')}} />
</div>
</body>
이때 자식 요소 onclick을 아래와 같이 수정하면 자식 요소를 클릭했을 때 '자식 요소 클릭' 알림창이 뜨는 것을 확인할 수 있다.
<body>
<div id='parent' onclick={() => {alert('부모 요소 클릭')}}>
<div id='child' onclick={(event) => {
event.stopPropagation();
alert('자식 요소 클릭');
}} />
</div>
</body>
`Event.stopImmediatePropagation()`
현재 이벤트가 버블링 단계에서 더 이상 전파되지 않도록 방지하는 것은 `.stopPropagation()`과 동일하지만, 동일한 요소에 발생한 동일한 이벤트에 대한 또다른 이벤트 핸들러의 실행도 막는다.
즉 하나의 요소에 같은 이벤트를 두 개를 적용하면 `.stopImmediatePropagation()`이 포함된 첫 번째 이벤트만 실행된다.
<div id="div2">
<div id="div2">
<button id="button">button</button>
</span>
</div>
const div1 = document.getElementById('div1');
const div2 = document.getElementById('div2');
const button = document.getElementById('button');
div1.addEventListener("click", () => console.log("div1 clicked"));
div2.addEventListener("click", () => console.log("div2 clicked"));
button.addEventListener('click', (e) => {
e.stopImmediatePropagation(); // stopImmediatePropagation()으로 이벤트 전파 방지
console.log('button1 clicked');
});
button.addEventListener("click", () => console.log("button2 clicked"));
참고로 React에서는 '이벤트 핸드러 어트리뷰트 방식'을 사용한다. 이는 동일한 html 요소에서 발생한 동일한 이벤트에 대해 하나 이상의 핸들러는 할당할 수 없는 방식이다. 따라서 `stopPropagation()`과 `stopImmediatePropagation()`을 비교하는데에 부적합할 수도 있어 위 코드들은 바닐라 JS로 작성되었다.
위 내용에서 이벤트 캡처링과 버블링에 대한 이야기가 나왔다. 이벤트 캡처링과 버블링은 최상위 요소에서 이벤트가 발생한 요소까지의 이동과 그 반대방향 이동 과정에서 발생하는 일이다.
이벤트 캡처링
최상위 요소에서 실제 이벤트가 발생한 요소에 이르기까지 자식 요소들을 타고 내려가 이벤트 핸들러가 있는지 검사하고, 있으면 해당 이벤트 핸들러를 호출한다.
이벤트 버블링
실제 이벤트가 발생한 요소에서 최상위 요소에 이를 때까지 부모 요소들을 타고 올라가 이벤트 핸들러가 있는지 검사하고, 있으면 해당 이벤트 핸들러를 호출한다. 거의 모든 이벤트는 버블링된다.
이때 하나의 요소에 여러 이벤트 핸들러가 적용된 경우, `stopPropagation()`이 적용된 이벤트에 대해서는 버블링을 막을 수 있지만 다른 이벤트 핸들러에 의해 발생한 버블링은 막을 수 없다. 이럴 때 `stopImmediatePropagation()`을 통해 다른 이벤트 핸들러를 모두 작동하지 않게 하면서 이에 따른 버블링도 막을 수 있다.
버블링은 아래 코드를 통해 확인할 수 있다.
<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>
더 자세한 내용은 JS 문서를 참고하자.
'Frontend > Today I Learned' 카테고리의 다른 글
[React] Hooks - useContext, memoization (0) | 2024.08.26 |
---|---|
[JS, redux] Redux Toolkit 기본 사용법 (0) | 2024.08.26 |
[JS, redux] Redux 소개 및 기본 사용법 (0) | 2024.08.19 |
[React] Hooks - useState, useEffect, useRef (0) | 2024.08.16 |
[CSS] 스크롤 바 스타일 (0) | 2024.08.13 |