티스토리 뷰
// 이벤트 버블링 (Event Bubbleing)
const content = document.querySelector('#content');
const title = document.querySelector('#title');
const list = document.querySelector('#list');
const items - document.querySelector('#item');
content.addEventListener('click', function() {
console.log('content Event');
});
title.addEventListener('click', function() {
console.log('title Event');
});
list.addEventListener('click', function() {
console.log('list Event');
});
for(let item of items) {
item.addEventListener('click', function() {
console.log('item Event');;
});
}
각 요소 별로 클릭 타입에 이벤트 요소들을 등록해 주었습니다.
그런데 각 영역을 클릭해보면 콘텐트는 문제없는 것 같은데 타이틀을 클릭하게 되면 타이틀 이벤트 핸들러와 같이 콘텐트 이벤트 핸들러도 동작하고 리스트도 똑같은 현상이 발생합니다.
심지어 아이템을 클릭하면 아이템, 리스트, 콘텐트 세 개의 이벤트가 모두 동시에 동작하는 것을 확인할 수 있습니다.
잠깐 아이템 이벤트 핸들러를 등록하는 부분을 코멘트 처리해두고 저장하고 실행해보면 리스트가 아니라 아이템 영역을 클릭했는데도 리스트와 콘텐트 이벤트 핸들러가 동작하는 모습을 확인할 수가 있습니다.
이러한 현상을 이벤트 버블링이라고 부릅니다.
버블링의 원리는 어떤 하나의 요소에 이벤트가 발생하게 되면 이 요소에 할당된 이벤트 핸들러가 동작하고 거기서 끝이 아니라 이어서 같은 타입의 이벤트에 한해서 부모 요소의 핸들러도 동작하게 되는 겁니다.
그렇게 가장 최상단의 윈도우 객체를 만날 때까지 이 과정이 반복되면서 요소 각각의 할당된 모든 이벤트 핸들러가 동작하는 원리입니다.
이벤트가 발생하면 가장 아래 자식 요소부터 부모 요소를 거슬러올라가면 발생하는 모양이 마치 물속에서 올라오는 거품과 닮았다고 해서 버를링이라는 이름이 붙었다고 합니다.
아무튼 이러한 이유때문에 아이템 영역을 클릭했지만 버블링에 의해서 아이템의 부모 요소인 리스트 그리고 리스트의 부모 요소인 콘텐트의 이벤트 핸들러도 함께 순서대로 동작했던 것입니다.
그런데 여기서 또 한 가지 주의해야 될 점이 있습니다. 이벤트 객체의 target 프로퍼티입니다.
각 이벤트 별로 이벤트 객체의 target을 같이 콘솔에 출력해보면 버블링이 되면서 각 이벤트 핸들러가 동작할 때 해당 핸들러가 등록된 요소가 target이 될 거라고 오해하는 경우가 있습니다.
// 이벤트 버블링 (Event Bubbleing)
const content = document.querySelector('#content');
const title = document.querySelector('#title');
const list = document.querySelector('#list');
const items - document.querySelector('#item');
content.addEventListener('click', function() {
console.log('content Event');
console.log(e.target);
});
title.addEventListener('click', function() {
console.log('title Event');
console.log(e.target);
});
list.addEventListener('click', function() {
console.log('list Event');
console.log(e.target);
});
for(let item of items) {
item.addEventListener('click', function() {
console.log('item Event');
console.log(e.target);
});
}
코드를 저장하고 실행해서 한번 확인해 보면 target은 변하지 않는 것을 확인할 수 있습니다. 사실 이 덕분에 부모 요소의 핸들러들이 최초의 이벤트가 발생한 위치를 정확하게 파악할 수 있게 됩니다.
이벤트 버블링이 일어나도 이벤트 객체의 target프로퍼티는 변하지 않고 처음 이벤트가 발생한 시작점을 담고 있다는 점 꼭 기억해두시면 좋을 것 같습니다.
그런데 만약 실행 중인 핸들러가 할당된 요소 그러니까 이벤트 핸들러가 등록된 요소에 접근하고 싶은 경우가 있을 수도 있습니다. 그럴 때는 currentTarget이라는 프로퍼티를 활용하면 됩니다.
currentTarget으로 코드를 수정하고 실행해보면 이제는 실제로 핸들러가 동작하는 요소가 출력되는 모습을 확인할 수가 있습니다. 자주 사용되지는 않겠지만 이벤트 객체에 이런 프로퍼티가 있다는 것도 함께 참고해두면 좋을 것 같습니다.
마지막으로는 이 버블링을 멈추는 방법입니다.
이벤트 객체에 stopPropagation이라는 메소드를 활용하면 간단하게 버블링을 멈출 수가 있습니다.
// 이벤트 버블링 (Event Bubbleing)
const content = document.querySelector('#content');
const title = document.querySelector('#title');
const list = document.querySelector('#list');
const items - document.querySelector('#item');
content.addEventListener('click', function() {
console.log('content Event');
console.log(e.target);
});
title.addEventListener('click', function() {
console.log('title Event');
console.log(e.target);
});
list.addEventListener('click', function() {
console.log('list Event');
console.log(e.target);
});
for(let item of items) {
item.addEventListener('click', function() {
console.log('item Event');
console.log(e.target);
e.stopPropapgation();
});
}
코드를 저장하고 실행해보면 다른 이벤트들은 버블링이 일어나지만 아이템에서는 버블링이 일어나지 않는 것을 확인할 수 있습니다.
메소드 하나로 이렇게 간단하게 버블링을 막을 수는 있지만 정말 필요한 경우가 아니라면 가급적 버블링을 막는 일은 피하는 것이 좋습니다.
지금처럼 이렇게 아이템 부분에서 이벤트 버블링을 막아버리게 되면 바로 위에 있는 리스트뿐만 아니라 모든 부모 요소의 입장에서 아이템 영역만큼의 이벤트를 발생시킬 범위가 사라져버리게 되는 겁니다.
예를 들어서 페이지 전체에 걸쳐서 어떤 이벤트를 만들고 싶은 경우에는 결국 document나 body같은 문서 전체를 다룰 수 있는 상위 요소의 이벤트 핸들러를 만들어줄 텐데 버블링이 막혀있는 구간이 존자하게 되면 당연히 클릭했을 때 버블링이 막혀 버리기 때문에 그 부분만 원하는 이벤트 결과를 얻지 못하는 겁니다.
사실 이벤트 버블링에 대해서 미리 잘 이해하고 이벤트를 설계한다면 버블링을 막아야 하는 일이 그리 많지는 않습니다.
그래도 혹시라도 필요한 상황이 올 수 있으니까 잘 기억해두면 좋을 것 같습니다.
'프론트엔드 > JavaScript' 카테고리의 다른 글
[이벤트 살펴보기] 10. 이벤트 위임 (0) | 2022.11.26 |
---|---|
[이벤트 살펴보기] 08. 캡쳐링 (0) | 2022.11.26 |
[이벤트 살펴보기] 05. 이벤트 객체 프로퍼티 (0) | 2022.11.21 |
[이벤트 살펴보기] 04. 이벤트 객체 (0) | 2022.11.21 |
[이벤트 살펴보기] 02. 다양한 이벤트 (0) | 2022.11.16 |
- Total
- Today
- Yesterday
- some
- 참조형 데이터
- redux-middleware
- 타입변환
- redux-thunk
- redux thunk
- 비교 연산자
- filter
- redux
- map
- 얕은복사
- find
- EVERY
- findindex
- null
- foreach
- 동적(dynamic) 언어
- 기본형 데이터
- redux middleware
- 느슨한 타입(loosely typed)
- undefined
- 불변 객체
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |