티스토리 뷰

우선 버블링이란 한 요소에서 이벤트가 발생하면, 이 요소에 할당된 핸들러가 동작하고, 이어서 부모 요소의 핸들러가 동작하는 것입니다. 가장 최상단의 조상요소를 만날 때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작합니다. 

 

이벤트 버블링이란 간단히 말하면 이벤트가 제일 깊은 요소에서 시작해 부모 요소로 거슬러 올라가며 이벤트를 전파하는 것입니다. 그 모습이 물속 거품과 닮았기 때문에 버블링이라 합니다. 

최근에 이 버블링이 적용되는 이벤트가 있고 아닌 이벤트가 있다는 것을 알게되어 정리하게 됐습니다. 

알아보니, 거의 모든 이벤트는 버블링이 된다고 나와있습니다. 예를 들어 focus 이벤트는 버블링이 되지 않습니다. 

🤍하단에 버블링이 발생하지 않는 이벤트들을 적어두었습니다.

 

event.target

부모 요소의 핸들러는 이벤트가 정확히 어디서 발생했는 지 등에 대한 자세한 정보를 얻을 수 있습니다. 

event.target 과 this(= event.currentTarget)은 다음과 같은 차이점을 가집니다.

  • event.target은 실제 이벤트가 시작된 '타깃' 요소를 말합니다. 버블링이 진행되어도 변하지 않습니다. 
  • this (currentTarget)은 이벤트를 핸들링하는 현재 요소(핸들러가 실제로 할당된 요소)
최근 mui v5으로 데스크탑 뷰 nav(여기서는 li요소)와 모바일 뷰 nav(여기서는 버튼 요소)를 하나의 핸들러로 관리하는 예시를 보게 되었고 각각의 요소에 target값을 가져오는 작업을 하고싶어서 알아보게 되었습니다.  

예시로 자식 요소로 div와 p를 가지고 있는 form 요소가 있다고 합시다. form에만 클릭 이벤트 핸들러를 할당하고 내부 요소를 클릭해도 클릭에 할당된 코드가 실행됩니다. 이유는 버블링이 일어나기 때문인데요. 이 버블링을 통해서 이벤트를 위임할 수 있습니다. 이벤트 위임이란 하위 요소의 이벤트를 상위 요소에 위임하여 하위 요소의 이벤트를 상위 요소에서 제어하는 것입니다. -> 이벤트 위임을 활용하면 이벤트 핸들러를 자식 요소에 전부 달아주지 않고 상위 이벤트 핸들러 하나만으로도 자식 요소가 몇이든 제어할 수 있게 됩니다.(이벤트 위임은 강력한 이벤트 핸들링 패턴이죠)

 

다시 본론으로 돌아와 이 form 태그의 p태그를 누르게 되면 event.target은 클릭된 현재 요소, 즉 p태그이며,

this(event.currentTarget)은 이벤트 핸들러가 달린 form을 가리킵니다. 

 

더 간단히 말하면 target은 이벤트가 트리거된 요소를 가리키고(유저가 원래 누른 요소) currentTarget은 이벤트 리스너가 실제로 붙어있는 요소를 가리키게 됩니다. 

📌ref: 스택 오버 플로우

버블링 중단하기

이벤트 버블링은 타깃 이벤트에서 시작해서 html 요소를 거쳐 document 객체를 만날 때가지 각 노드에서 모두 발생합니다.

몇몇 이벤트는 window 객체까지 거슬러 올라가기도 합니다. 이때도 모든 핸들러가 호출됩니다. 

여기서 핸들러에게 이벤트를 완전히 처리한 후 버블링을 중단하도록 명령할 수도 있습니다. 

event객체의 메서드인 event.stopPropagation()을 사용하면 됩니다. 

추가적으로 한 요소의 특정 이벤트를 처리하는 핸들러가 여러 개인 상황에서는 핸들러 중 하나가 버블링을 멈추더라도 나머지 핸들러는 여전히 동작하게 됩니다. stopPropagation은 위쪽으로 일어나는 버블링은 막아주지만, 다른 핸들러들이 동작하는 것은 막지 못합니다(같은 위치에 존재하기 때문에 그렇지 않을까 싶습니다).

여기서 버블링을 멈추고, 요소에 할당된 다른 핸들러의 동작도 막으려면 event.stopImmediatePropagation()을 사용해야 합니다. 이 메서드를 사용하면 요소에 할당된 특정 이벤트를 처리하는 핸들러 모두가 동작하지 않습니다.

 

TIP 같은 요소와 같은 단계에 설정한 리스너는 설정한 순서대로 동작합니다. (위부터 아래로)
: 특정 요소에 addEventListener를 사용해 한 단계에 이벤트 핸들러를 여러 개 설정했다면 이 핸들러들은 설정한 순서대로 동작하게 됩니다. 

 

🤔버블링을 중단할 수는 있지만 웬만하면 버블링을 막지 말아야 합니다(?)

예를 들어, 유저의 행동 패턴을 분석하기 위해 window내에 발생하는 클릭 이벤트를 전부 감지하기로 했을 때, stopPropagation으로 버블링을 막아놓은 영역은 분석 시스템의 코드가 동작하지 않는 dead zone이 됩니다. 

버블링을 막아야하는 경우는 거의 없으며 막아야 해결되는 문제라면 커스텀 이벤트 등을 활용하여 해결할 수 있습니다.

-> 커스텀 이벤트의 경우도 알아본 결과, 양날의 검이라는 생각이 드네요(마냥 좋은 방법인지는 잘 모르겠습니다 아무래도 익숙하지 않고 손쉬운 방법이 아니라서 그런걸까요?). 리액트에서 커스텀 이벤트를 사용하여 활용하는 아티클을 찾아봤습니다. 

리액트 커스텀 이벤트 관련 아티클

 

 

all ref: https://ko.javascript.info/bubbling-and-capturing

 

버블링과 캡처링

 

ko.javascript.info


대부분의 이벤트가 버블링이 일어난다고 했으니...

그렇다면 버블링이 일어나지 않는 이벤트는 뭔가?

HTML frame/object

  • load
  • unload
  • scroll (except that a scroll event on document must bubble to the window)

HTML form

  • focus
  • blur

Mutation

  • DOMNodeRemovedFromDocument
  • DOMNodeInsertedIntoDocument

Progress

  • loadstart
  • progress
  • error
  • abort
  • load
  • loadend

From: https://en.wikipedia.org/wiki/DOM_events#Events

 

를 제외한 모든 이벤트는 버블링이 일어난다고 볼 수 있습니다.

댓글