https://ko.javascript.info/bubbling-and-capturing
서론
<div onclick="alert('div에 할당한 핸들러!')">
<em><code>EM</code>을 클릭했는데도 <code>DIV</code>에 할당한 핸들러가 동작합니다.</em>
</div>
위의 코드에서 `<em/>` 를 클릭하면 div에 할당한 이벤트핸들러가 동작한다. 왜그럴까?
결론은 버블링 때문이다.
버블링
버블링이란, 한 요소에 이벤트가 발생하면, 이 요소에 할당된 핸들러가 동작하고, 이어서 부모요소의 핸들러가 동작한다.
가장 최 상단의 조상 요소를 만날때 까지 이 과정이 반복되며, 요소 각각에 할당된 핸들러가 동작한다. 그리고 document 객체를 만날때 까지 계속된다.
<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>
위의 코드를 실행하고 `<p/>` 를 클릭하면, `form` `div` `p` 에 할당된 이벤트핸들러가 실행된다. 위에서 설명했던 것 처럼 이벤트버블링이 일어난 것이다.
(정확히는, `<p/>` 요소 클릭시, `p` -> `div` -> `form` 순서로 실행된다.)
이런 흐름을, 이벤트버블링 이라고 한다. 이벤트가 제일 깊은 곳에 있는 요소에서 부터 시작해 부모 요소를 거슬러 올라가는 모양이 마치 Bubble 과 닮았기 때문이다.
(모든 이벤트가 버블링이 일어나는 것은 아니다. 몇몇 이벤트들은 발생하지 않는다.)
event.target
핸들러는 이벤트가 정확히 어디서 발생했는지에 대한 정보를 얻을 수 있다.
이벤트가 발생한 가장 안쪽의 요소는 target 요소라 불리고, event.target 을 사용해 접근할 수 있다.
event.target: 실제 이벤트가 시작된 요소. 버블링이 진행되어도 변하지 않음.
event.currentTarget(this): 현재 실행중인 핸들러가 할당된 요소를 참조
버블링 중단하기
핸들러에게 이벤트를 처리하고 난 후 버블링을 중단하도록 명령할 수 있다.
event.stopPropagation()
캡처링
DOM 이벤트에서 정의한 이벤트 흐름엔 3가지 단계가 있다.
캡처링 단계: 이벤트가 하위 요소로 전파되는 단계
타깃 단계: 이벤트가 실제 타깃 요소에 전달되는 단계
버블링 단계: 이벤트가 상위 요소로 전파되는 단계
<td>를 클릭하면 이벤트가 최상위 조상에서 시작해 아래로 전파되고(캡처링 단계),
이벤트가 타깃 요소에 도착해 실행된 후(타깃 단계),
다시 위로 전파된다(버블링 단계).
이런 과정을 통해 요소에 할당된 이벤트 핸들러가 호출된다.
<form>FORM
<div>DIV
<p>P</p>
</div>
</form>
<script>
for(let elem of document.querySelectorAll('*')) {
elem.addEventListener("click", e => alert(`캡쳐링: ${elem.tagName}`), true);
elem.addEventListener("click", e => alert(`버블링: ${elem.tagName}`));
}
</script>
<p/> 클릭시 다음과 같은 순서로 이벤트가 전달된다.
1: HTML → BODY → FORM → DIV (캡처링 단계, 첫 번째 리스너)
2: P (타깃 단계, 캡쳐링과 버블링 둘 다에 리스너를 설정했기 때문에 두 번 호출)
3: DIV → FORM → BODY → HTML (버블링 단계, 두 번째 리스너)
'🌳Frontend > etc' 카테고리의 다른 글
package.json 의 version 과 틸드 tilde(~) 그리고 캐럿 caret(^) (0) | 2023.06.15 |
---|---|
포커스된 요소의 부모요소에 스타일링 (2) | 2023.06.15 |
배포하면 Production(운영)을 바라보던 사용자는 어떻게 될까 (캐시, 브라우저 캐시, 캐시의 종류) (0) | 2023.05.26 |
캐시(Cache) 제어 Header 종류 (0) | 2023.05.26 |
인증과 사용자 세션 1 (0) | 2023.04.25 |