25. 이벤트 전파 📢

EEuglena·2023년 8월 22일
0

JavaScript30

목록 보기
23/27
post-thumbnail

목표

강의에서 소개하는 이벤트 전파에 관련된 사항을 정리해 보자.

함수에서 this

본론으로 들어가기 전에 우선 함수에서 this를 처리하는 방식을 간단히 살펴보려고 한다.

페이지는 총 3개의 div가 중첩된 구조이며(body > .one > .two > .three) 마우스 버튼을 누를 때는 화살표 함수로 this를 출력하고 버튼을 뗄 때는 함수 표현식으로 this를 출력하도록 했다. 결과는 다음과 같다.

화살표 함수에서는 this가 window로, 함수 표현식에서는 this가 이벤트를 처리하는 대상으로 지정된다. 이는 화살표 함수에서 this가 바인딩되지 않기 때문에 일어나는 일로, 컨텍스트를 따라 올라가며 가장 가까운 this를 가져온다. 이 경우 전역 컨텍스트에서 이벤트 리스너가 호출됐기 때문에 전역 객체인 window를 가리킨다. 갑자기 이 차이를 설명하는 이유는 지금부터 살펴볼 이벤트 전파에서 이벤트 타깃과 이벤트를 처리하는 this를 비교할 것이기 때문에 this를 활용하는 방법을 알고 있어야 하기 때문이다.

이벤트 타깃과 this

평범한 onClick 리스너를 등록하여 this와 이벤트 타깃의 이름을 각각 출력하도록 했다. 이때 가장 안쪽에 있는 div.three를 클릭한 결과를 확인하였다.

콘솔창을 보면 이벤트 타깃은 three로 전부 동일하지만 this는 three, two, one이 각각 한 번씩 출력된다. 이는 이전에 이벤트 위임에서 알아봤던 이벤트 전파와 관련된 현상이다.

이벤트 전파

페이지에서 이벤트가 발생하면 이벤트가 발생한 대상이 이벤트 타깃으로 정해진다. HTML 요소는 서로 중첩될 수 있으므로 이벤트 타깃의 부모 요소들이 있을 것이다. 이때 이벤트는 총 3단계에 걸쳐 진행되며, document에서 이벤트 타깃까지 내려가는 캡처링 단계, 이벤트 타깃에서 이벤트를 처리하는 타깃 단계, 다시 document까지 올라가는 버블링 단계를 거친다. 가장 많이 사용되는 타깃 단계는 특별히 설명할 내용이 없을 것 같다. 버블링 단계는 이벤트 위임에서 알아본 적이 있다.

위 이미지는 전 문단의 예시에 body와 document까지 이벤트 리스너를 등록한 모습이다. 이벤트 타깃은 div.three부터 시작하여 document까지 이벤트가 전파되는 것을 확인할 수 있다.

이벤트의 eventPhase 속성을 통해 이를 확실히 알아볼 수 있다. 1은 캡처링, 2는 타깃, 3은 버블링 단계를 각각 나타낸다. 이처럼 이벤트는 기본적으로 타깃 단계와 버블링 단계에 실행된다.

이벤트 캡처링

이벤트 캡처링 단계에서 이벤트를 처리하기 위해서는 addEventListener에 세 번째 매개변수로 {capture: true} 또는 true 를 전달하면 된다. 이 경우 버블링 단계에서 이벤트를 처리하지 않고 캡처링 단계에서 이벤트를 처리하게 된다.

document에서부터 타깃까지 차례대로 내려가는 과정을 볼 수 있다. 타깃은 여전히 타깃 단계에서 실행된다. 이를 정리하면 다음과 같다.

먼저 document에서 타깃까지 내려가며 {capture: true} 로 설정된 이벤트를 실행한다(eventPhase = 1). 그 다음 타깃에서 이벤트를 실행하고 (eventPhase = 2) 다시 document까지 올라가며 {capture: true} 로 설정되지 않은 이벤트를 실행한다(eventPhase = 3).

addEventListener의 세 번째 매개변수

addEventListener 호출은 다음과 같은 방법으로 할 수 있다.

addEventListener(type, listener);
addEventListener(type, listener, useCapture);
addEventListener(type, listener, options);

첫 번째는 가장 일반적인 방법으로 이벤트와 리스너를 전달하는 방식이다. 두 번째는 true를 전달할 경우 캡처링 단계에서 실행, false를 전달할 경우 버블링 단계에서 실행하도록 하는 방식이다. 마지막은 리스너의 옵션을 전달할 수 있는데, capture을 이용해서 이벤트 페이즈를 조절하는 방법을 위에서 살펴보았다. 강의에서는 추가로 once를 소개하고 있다.

capture를 설정했던 것과 비슷하게 {once: true} 를 전달할 수 있다. 이렇게 등록된 리스너는 딱 한 번 작동한 뒤 제거된다.

버튼을 다섯 번 클릭하였지만 onFirstClick은 한 번만 작동하고 onClick만 다섯 번 작동하였다. 다만 once는 IE를 포함한 일부 구버전 브라우저에서는 작동하지 않는다.

이외에도 preventDefault를 호출하지 않는다는 {passive: true} 와 AbortController의 abort 신호를 받았을 때 리스너를 제거하는 {signal: AbortController.signal} 옵션이 존재한다.

소스 코드

Visit Github Repository

0개의 댓글