버블링(bubbling)
버블링은 한 요소에 이벤트가 발생하면, 이 요소에 할당된 핸들러가 동작하고, 이어서 부모 요소의 핸들러가 동작합니다. 가장 최상단의 조상요소를 만날 때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작합니다.
가장 안쪽의 p 태그를 클릭하면 순서대로 다음과 같은 일이 벌어집니다.
1. p 태그에 할당된 onclick 핸들러가 동작합니다.
2. 바깥의 div 태그에 할당된 onclick 핸들러가 동작합니다.
3. 그 바깥의 form 태그에 할당된 onclick 핸들러가 동작합니다.
4. documenet 객체를 만날 때까지, 각 요소에 할당된 onclick 핸들러가 동작합니다.
이런 동작 방식 때문에 p태그 요소를 클릭하면 p > div > form 순서로 3개의 얼럿 창이 뜨게 됩니다.
이런 흐름을 '이벤트 버블링'이라고 부릅니다. 이벤트가 제일 깊은 곳에 있는 요소에서 시작해 부모 요소를 거슬러 올라가며 발생하는 모양이 마치 물속 거품(bubble)과 닮았기 때문입니다.
event.target
부모 요소의 핸들러는 이벤트가 정확히 어디서 발생했는지 등에 대한 자세한 정보를 얻을 수 있습니다.
이벤트가 발생한 가장 안쪽의 요소는 타깃(target)요소라고 불리고, event.target을 사용해 접근할 수 있습니다.
- event.target은 실제 이벤트가 시작된 '타깃'요소입니다. 버블링이 진행되어도 변하지 않습니다.
- this는 '현재' 요소로, 현재 실행 중인 핸들러가 할당된 요소를 참조합니다.
버블링 중단하기
이벤트 버블링은 타깃 이벤트에서 시작해서 html 태그 요소를 거쳐 document 객체를 만날 때까지 각 노드에서 모두 발생합니다. 몇몇 이벤트는 window 객체까지 거슬러 올라가기도 합니다. 이 때도 모든 핸들러가 호출됩니다.
그런데 핸들러에게 이벤트를 완전히 처리하고 난 후 버블링을 중단하도록 명령할 수도 있습니다.
이벤트 객체의 메서드인 event.stopPropagation()을 사용하면 됩니다.
event.stopPropagation()은 위쪽으로 일어나는 버블링은 막아주지만, 다른 핸들러들이 동작하는건 막지 못합니다.
만약 버블링을 멈추고, 요소에 할당된 다른 핸들러의 동작도 막으려면 event.stopImmediatePropagation()을 사용해야 합니다. 이 메서드를 사용하면 요소에 할당된 특정 이벤트를 처리하는 핸들러 모두가 동작하지 않습니다.
캡처링
이벤트엔 버블링 이외에도 캡처링(capturing)이라는 흐름이 존재합니다.
표준 DOM 이벤트에서 정의한 이벤트 흐름에는 3가지 단계가 있습니디ㅏ.
1. 캡처링 단계 - 이벤트가 하위 요소로 전파되는 단계
2. 타깃 단계 - 이벤트가 실제 타깃 요소에 전달되는 단계
3. 버블링 단계 - 이벤트가 상위 요소로 전파되는 단계
최하위 div를 클릭하면 이벤트가 최상위 조상에서 시작해서 아래로 전파되고(빨간부분, 캡처링 단계), 이벤트가 타깃 요소에 도착해 실행된 후(주황부분,타깃 단계), 다시 위로 전파됩니다(노랑부분,버블링 단계). 이런 과정을 통해 요소에 할당된 이벤트 핸들러가 호출됩니다.
capture옵션은 두 가지 값을 가질 수 있습니다.
- false 이면(default) 핸들러는 버블링 단계에서 동작합니다.
- true 이면 핸들러는 캡처링 단계에서 동작합니다.
공식적으로는 총 3개의 흐름이 있지만, 이벤트가 실제 타깃 요소에 전달되는 단계인 '타깃 단계'는 별도로 처리되지 않습니다. 캡처링과 버블링 단계의 핸들러는 타깃 단계에서 트리거됩니다.
p를 클릭하면 다음과 같은 순서로 이벤트가 전달됩니다.
1. html > body > form > div (캡처링 단게, 첫 번째 리스너)
2. p (타깃 단게, 캡처링과 버블링 둘 다에 리스너를 설정했기 때문에 두 번 호출됩니다.)
3. div > form > body > html (버블링 단계, 두 번째 리스너)
event.eventPhase 프로퍼티를 이용하면 현재 발생 중인 이벤트 흐름의 단계를 알 수 있습니다. 반환되는 정수값에 따라 이벤트 흐름의 현재 실행 단계를 구분할 수 있습니다.
하지만 핸들러를 통해 흐름 단계를 알 수 있기 때문에 이 프로퍼티는 자주 사용되지 않습니다.
다음의 사이트에서 버블링과 캡처링을 한눈에 볼 수 있습니다.
참고
'javascript' 카테고리의 다른 글
[JavaScript] html2canvas 로 화면 캡처 후 저장하기 (React) (0) | 2022.09.21 |
---|---|
[Javascript] Base64 인코드, 디코드 하는 방법- atob(), btoa() (0) | 2022.07.16 |
[Javascript] base64로 인코딩 된 문자열을 ArrayBuffer로 디코딩하기(base64 to array buffer) (0) | 2022.07.15 |
[Javascript] Hash(해시) - 해시 테이블(hash table) 구현하기 (0) | 2022.07.04 |
[Javascript] 배열 정렬하기 sort() (0) | 2022.06.27 |
댓글