이벤트가 발생하면 이벤트가 발생한 가장 안쪽 요소가 '타깃 요소(event.target)'가 됩니다.
이벤트는 document에서 시작해 DOM 트리를 따라 event.target까지 내려갑니다. 이벤트는 트리를 따라 내려가면서 addEventListener(..., true)로 할당한 핸들러를 동작시킵니다. addEventListener(..., true)의 true는 {capture: true}의 축약형입니다.
이후 타깃 요소에 설정된 핸들러가 호출됩니다.
이후엔 이벤트가 event.target부터 시작해서 다시 최상위 노드까지 전달되면서 각 요소에 on로 할당한 핸들러와 addEventListener로 할당한 핸들러를 동작시킵니다. addEventListener로 할당한 핸들러 중, 세 번째 인수가 없거나 false, {capture: false}인 핸들러만 호출됩니다.
각 핸들러는 아래와 같은 event 객체의 프로퍼티에 접근할 수 있습니다.
event.target – 이벤트가 발생한 가장 안쪽의 요소
event.currentTarget (=this) – 이벤트를 핸들링 하는 현재 요소 (핸들러가 실제 할당된 요소)
event.eventPhase – 현재 이벤트 흐름 단계(캡처링=1, 타깃=2, 버블링=3)
핸들러에서 event.stopPropagation()을 사용해 이벤트 버블링을 멈출 수 있습니다. 다만, 이 방법은 추천하지 않습니다. 지금은 상위 요소에서 이벤트가 어떻게 쓰일지 확실치 않더라도, 추후에 버블링이 필요한 경우가 생기기 때문입니다.
캡처링 단계는 거의 쓰이지 않고, 주로 버블링 단계의 이벤트만 다뤄집니다. 이렇게 된 데는 논리적 배경이 있습니다.
현실에서 사고가 발생하면 지역 경찰이 먼저 사고를 조사합니다. 그 지역에 대해 가장 잘 아는 기관은 지역 경찰이기 때문입니다. 추가 조사가 필요하다면 그 이후에 상위 기관이 사건을 넘겨받습니다.
이벤트 핸들러도 이와 같은 논리로 만들어졌습니다. 특정 요소에 할당된 핸들러는 그 요소에 대한 자세한 사항과 무슨 일을 해야 할지 가장 잘 알고 있습니다. <td>
에 할당된 핸들러는 <td>
에 대한 모든 것을 알고 있기 때문에 <td>
를 다루는데 가장 적합합니다. 따라서 <td>
를 다룰 기회를 이 요소에 할당된 핸들러에게 가장 먼저 주는 것입니다.
버블링과 캡처링은 '이벤트 위임(event delegation)'의 토대가 됩니다. 이벤트 위임은 강력한 이벤트 핸들링 패턴입니다.