버블링(Bubbling)이란
가장 깊게 중첩된 요소에 이벤트가 발생했을 때 이벤트가 위로 (bubble up) 전달 되는 것을 의미합니다.
예제
body 안의 모든 태그들에 click 이벤트가 발생시 log를 출력하도록 만든 예제입니다.
See the Pen Bubbling Test2 by J-Plum (@J-Plum) on CodePen.
a태그인 fruit 를 클릭했을때 body까지 alert가 출력됩니다.
자식 요소에서 발생한 이벤트 객체는 부모를 통해 상위 요소로 전달됩니다.
이벤트가 상위 요소로 올라가는것이 물속의 거품처럼 보인다고해서 이벤트 버블링이라고 합니다.
버블링이 일어나지 않는 이벤트와 대체제
- focus (x) -> focusin (o)
- blur (x) -> focusout (o)
- mouseenter (x) -> mouseover (o)
- mouseleave (x) -> mouseout (o)
버블링을 막는 방법?
stopPropagation()을 사용하면 버블링을 막을 수 있습니다.
하지만 막을 수 있지만.stopPropagation을 사용해서 막는건 좋은 방법은 아니라고 합니다
웹 사이트를 이용하는 유저의 동향을 파악 및 데이터를 수집하기 위해, 웹의 애널리틱스는 자주 사용하는데
이 애널리틱스는 버블링을 이용해서 데이터를 수집하기때문에 버블링을 막을경우
데이터 수집이 재대로 되지 않을 수 있다고 합니다.
아래는 stopPropagation과 다른 방법으로 해결했습니다.
See the Pen Bubbling Test by J-Plum (@J-Plum) on CodePen.
이벤트 캡처링
버블링과 다르게 가장 상단의 요소(브라우저)로부터 아래로 내려오는 것을 말합니다.
이벤트는 3단개의 흐름이 있습니다.
캡처링 단계 -> 타깃 단계 -> 버블링 단계
위 흐름에서 캡처링의 흐름을 확인하려면 addEventListener의 capture옵션을 ture로 설정해야합니다.
???.addEventListener(... , {captrue: true})
???.addEventListener(... , true)
동일하게 동작합니다
capture는 두가지 옵션이 있습니다.
- false 이면 (default) 버블링 단계 동작
- true 이면 캡처링 단계 동작
이벤트 위임
자신에게 발생한 이벤트를 다른 요소에서 처리하는 방법입니다.
하위 요소에서 동일한 이벤트를 처리하는 반복적인 일을 보다 편리하게 해결이 가능합니다.
상위 요소에서 이벤트를 제어한다면 보다 편리하게 관리를 할 수 있습니다.
<body>
<div id="box">
<ul id="list">
<li id="apple" class="active"><a href="#">Apple</a></li>
<li id="orange"><a href="#">Orange</a></li>
<li id="banana"><a href="#">Banana</a></li>
</ul>
</div>
<script async>
const list = document.querySelector("#list");
const listChildren = list.children;
list.addEventListener('click',(e)=>{
for(let li of listChildren){
li.classList.remove('active');
}
e.target.classList.add('active');
})
</script>
</body>
See the Pen Untitled by J-Plum (@J-Plum) on CodePen.
클릭시 active 라는 클래스를 추가해서 강조를 해줍니다. 최초 실행시
Apple에 지정되어 있습니다. 이벤트는 ul 태그에 걸려있으며 클릭시 for of문을 이용해 모든 li의 클래스를 지우고
그 후 이벤트 타겟에 active클래스를 추가해서 강조하는 방식입니다.
위 방식은 ul태그에 이벤트를 걸어 자식태그인 li 에 이벤트를 위임 시키는 방식입니다
하지만 li를 클릭시에는 정상적으로 작동 하지만 a 태그를 클릭시 의도한 바와 다르게 작동합니다
이는 버블링에 의해 발생하는 현상으로
ul 의 자식인 li> a 까지 이벤트가 위임이 된 것 입니다.
문제 해결
e.target 은 이벤트가 발생한 요소이며, e.currentTarget 은 이벤트 핸들러가 등록된 요소입니다.
이벤트가 발생한건 orange인 li 태그 이며 (e.target) 이벤트가 등록된건 list 인 ul태그 (e.currentTarget)입니다.
이벤트 위임을 사용하지 않았다면 target과 currentTarget은 같았겠지만 지금은 다른 상황입니다.
a 태그를 클릭시 currentTarget은 list이며 target은 a입니다.
저희가 원하는 것은 a태그를 클릭 하더라도 li 태그의 색상의 변경입니다.
target의 tagName이 "A" 일때 target을 A가아닌 부모노드 (li)를 지정하도록 했습니다.
그런데 .ul 태그를 클릭했더니 ul 태그도 바뀌는 일이 생겼습니다.
target과 currentTarget을 비교하여 동일할 경우 에는 return로 넘겨주었습니다만.
for문의 위치가 if문보다 상단에있어, class를 삭제후 else if에 걸리면, active 클래스가 전부 사라지는 현상이 있어서
for문의 위치를 if문 밑으로 변경하였습니다.
그러면 else if에 return에 걸리더라도 동작을 안할뿐더러 클래스를 지우지 않기 때문에 정상 작동합니다.
아래는 결과물입니다.
See the Pen Untitled by J-Plum (@J-Plum) on CodePen.
참고
'JavaScript > JavaScript' 카테고리의 다른 글
[JavaScript] 구조 분해 할당(Destructuring) (0) | 2023.03.04 |
---|---|
[JavaScript] 자바스크립트의 this란? (0) | 2023.03.03 |
[JavaScript] Node와 Element / DOM 탐색하기 / 유사배열객체 (0) | 2023.03.01 |
[JavaScript] document 객체 (2) | 2023.03.01 |
[JavaScript] Window Object (0) | 2023.03.01 |