자바스크립트에서 이벤트 버블링(Event Bubbling)은 HTML 요소에서 발생하는 이벤트가 해당 요소의 상위 요소로 전파되는 현상을 말합니다. 이는 이벤트가 발생한 요소부터 상위 요소까지 순서대로 이벤트 핸들러가 호출되는 구조를 가지게 됩니다.
1. 이벤트 버블링의 개념
예를 들어, 다음과 같은 HTML 구조가 있다고 가정해봅시다.
<div id="outer">
<div id="inner"></div>
</div>
이 구조에서 #inner 요소에서 클릭 이벤트가 발생하면, 이벤트는 #inner -> #outer 순서로 전파되게 됩니다. 따라서, #inner 요소에 이벤트 핸들러가 등록되어 있고, 해당 핸들러가 실행되면, 이벤트는 자동으로 #outer 요소에도 전달되며, #outer 요소에 등록된 이벤트 핸들러도 실행됩니다.
이벤트 버블링은 일반적으로 이벤트 핸들러를 여러 요소에서 공유할 때 유용합니다. 예를 들어, 한 페이지에 있는 모든 버튼에 동일한 이벤트 핸들러를 등록하고 싶을 때, 버튼 각각에 핸들러를 등록하는 것보다는 해당 상위 요소에 핸들러를 등록하고, 이벤트 버블링을 이용해서 모든 버튼에서 핸들러를 호출하는 것이 더 간단하고 효율적입니다.
하지만, 이벤트 버블링이 무한정 계속되면 성능 이슈가 발생할 수 있습니다. 이를 방지하기 위해 이벤트 캡처링(Event Capturing)이라는 개념도 존재합니다. 이벤트 캡처링은 이벤트가 상위 요소로 전파되기 전에 하위 요소부터 전파되는 방식으로 작동합니다. 이벤트 캡처링과 이벤트 버블링을 함께 사용하여, 이벤트 전파를 효율적으로 관리할 수 있습니다.
2. 예제 코드
다음은 간단한 예제 코드입니다.
<div id="outer">
<div id="middle">
<div id="inner"></div>
</div>
</div>
const outer = document.querySelector('#outer');
const middle = document.querySelector('#middle');
const inner = document.querySelector('#inner');
outer.addEventListener('click', () => {
console.log('Outer clicked');
});
middle.addEventListener('click', () => {
console.log('Middle clicked');
});
inner.addEventListener('click', () => {
console.log('Inner clicked');
});
위 코드에서는 세 개의 div 요소가 중첩되어 있습니다. 이 요소들에 각각 클릭 이벤트 핸들러를 등록하고, 이벤트 버블링이 어떻게 작동하는지 살펴보겠습니다.
만약 #inner 요소를 클릭하면, Inner clicked 메시지가 출력됩니다. 이후, 이벤트가 #middle 요소로 전파되어, Middle clicked 메시지가 출력됩니다. 마지막으로, 이벤트가 #outer 요소로 전파되어, Outer clicked 메시지가 출력됩니다. 따라서, 이벤트는 자식 요소에서 시작해 부모 요소로 이동하면서 이벤트 핸들러를 호출하는 형태로 전파됩니다.
3. 이벤트 전파를 막는 방법
1) event.stopPropagation()
event.stopPropagation() 메서드를 호출하여 이벤트 전파를 중지할 수 있습니다. 이 메서드는 현재 이벤트가 상위 요소로 전파되지 않도록 하며, 즉시 이벤트 핸들러의 실행을 중지합니다. 이 메서드는 해당 이벤트에 대해서만 적용되며, 다른 이벤트에 대해서는 적용되지 않습니다. 예를 들어, 다음 코드는 #inner 요소에서 클릭 이벤트가 발생했을 때, 이벤트가 #middle 요소까지만 전파되도록 합니다.
inner.addEventListener('click', (event) => {
console.log('Inner clicked');
event.stopPropagation();
});
2) event.preventDefault()
event.preventDefault() 메서드를 호출하여 기본 동작을 막을 수 있습니다. 이 메서드는 현재 이벤트의 기본 동작을 취소합니다. 예를 들어, 링크 클릭 이벤트에 대해서는 이 메서드를 호출하여 브라우저가 링크를 따라가는 기본 동작을 막을 수 있습니다. 다음은 링크 클릭 이벤트에 대해서 기본 동작을 막는 예제입니다.
const link = document.querySelector('a');
link.addEventListener('click', (event) => {
console.log('Link clicked');
event.preventDefault();
});
위 코드에서, preventDefault() 메서드 호출은 링크 클릭 이벤트의 기본 동작인 페이지 이동을 막습니다. 대신에, 콘솔에 Link clicked가 출력됩니다.
4. 주의해야 사항
- 이벤트 핸들러 등록 시, 핸들러 함수 내부에서 사용하는 변수나 함수가 전역 범위에 존재하는 경우가 있습니다. 이 경우, 이벤트 발생 시마다 해당 변수나 함수가 전역 범위에서 검색되어야 하므로, 성능 문제를 발생시킬 수 있습니다. 따라서, 이벤트 핸들러에서 사용하는 변수나 함수는 가능한 지역 범위에 정의하고, 필요한 경우 이벤트 핸들러 함수의 매개변수로 전달하는 것이 좋습니다.
- 이벤트 핸들러 함수 내부에서 this 키워드를 사용하는 경우, this가 핸들러 함수가 등록된 요소를 가리키지 않을 수 있습니다. 이는 함수를 호출하는 방식에 따라 결정됩니다. 이벤트 핸들러 함수 내부에서 핸들러 함수가 등록된 요소를 참조해야 하는 경우, event.currentTarget 속성을 사용하여 핸들러 함수가 등록된 요소를 명시적으로 참조하는 것이 좋습니다.
- 이벤트 버블링이나 캡처링을 사용하는 경우, 이벤트 핸들러가 호출되는 순서를 고려해야 합니다. 이벤트 버블링은 하위 요소에서 상위 요소로 이벤트가 전파되므로, 하위 요소에서 등록된 이벤트 핸들러가 상위 요소에서 등록된 이벤트 핸들러보다 먼저 호출됩니다. 이벤트 캡처링은 상위 요소에서 하위 요소로 이벤트가 전파되므로, 상위 요소에서 등록된 이벤트 핸들러가 하위 요소에서 등록된 이벤트 핸들러보다 먼저 호출됩니다.
- 이벤트 처리 중에는 핸들러 함수에서 예외가 발생할 수 있습니다. 이는 JavaScript의 특성상 언제든지 발생할 수 있는 문제이므로, 항상 예외 처리를 해주는 것이 좋습니다. 예를 들어, try...catch 문을 사용하여 예외를 처리할 수 있습니다.
'자바스크립트' 카테고리의 다른 글
[자바스크립트] 콜스택 (Call stack) (0) | 2023.03.09 |
---|---|
[자바스크립트] 호이스팅 (Hoisting) (0) | 2023.03.08 |
[자바스크립트] 폴리필 (Polyfill) (0) | 2023.03.08 |
[자바스크립트] 디스트럭처링 (Destructuring) (0) | 2023.03.08 |
[자바스크립트] 이벤트 루프 (event loop) (0) | 2023.03.07 |
댓글