[JavaScript] 캡쳐링 & 버블링

HYl·2022년 2월 17일
0

캡쳐링 시기와 버블링 시기는 브라우저에서 이벤트를 처리하는 순서와 밀접하게 관련이 있다. 일반적으로 이벤트리스너(콜백함수)를 등록하게 되면 기본적으로 버블링 단계에서 등록된 콜백함수가 호출이된다.
(대부분의 캡처링 단계에서 무언가를 처리해줘야 했던 적은 없다. 기본적으로 버블링 단계에서 특정 이벤트를 처리 해주게되고, 이벤트 위임을 활용하게 된다.)

  • 캡처링 단계에서 무언가를 해주고 싶다면, 이벤트 리스너를 등록할 때 옵션을 명시적으로 전달해주어야 한다.
wrapper.addEventListener("click", (event) => {
    console.log(`wrapper: ${event.currentTarget}, ${event.target}`);
   },  { capture: true, }
 );

버블링이 발생하는 조건 ?

  • 버블링은 부모/자식 구조에 해당한다. (형제 노드에서는 발생하지 않는다.)
  • 부모/자식 간의 이벤트가 동일한 이벤트여야 한다.
<div> 
  <span>버블링</span>
</div>
  • 이벤트 종류
    • 부모/자식 구조에서 동일한 이벤트만 버블링이 되어진다.
      1. 위의 div에 클릭 이벤트를 등록해놓고, 자식 span 요소에 동일한 클릭 이벤트를 등록해놓으면, span을 클릭하면 div 요소에 등록해 놓은 클릭 이벤트 콜백이 실행이 된다. (버블링 조건 O)
      1. 부모인 div 요소에는 마우스다운 이벤트를 등록해놓고, 자식인 span 요소에는 클릭 이벤트를 등록해놓으면 span을 클릭했을 때 div 요소에 등록해놓은 마우스다운 이벤트 콜백이 실행되지 않는다 ! (버블링 조건 X)

버블링 예제.

	<div>
      <span>Click</span>
    </div>
    
    <script>
      const parent = document.querySelector('div');
      const children = document.querySelector('span');

      parent.addEventListener('click', e => {
        console.log('부모 event');
      });
      
      children.addEventListener('click', e => {
        console.log('자식 event');
      });
    </script>


위의 사진을 보면, Click을 누르면 오른쪽의 console에 찍히는 것과 같이 span의 event를 발동시켰는데, 부모인 div의 함수도 같이 실행되는 것을 알 수 있다.
만약, 자식의 event만 실행시키고 싶을 때에는 2가지 방법이 있다.

버블링을 방지하는 방법

1. stopPropagation

  • stopPropagation() 메서드는 현재 이벤트가 캡처링/버블링 단계에서 더 이상 전파되지 않도록 방지한다.
  	<div>
      <span>Click</span>
    </div>
    
    <script>
      const parent = document.querySelector('div');
      const children = document.querySelector('span');

      parent.addEventListener('click', e => {
        console.log('부모 event');
      });
      
      children.addEventListener('click', e => {
      	e.stopPropagation();
        console.log('자식 event');
      });
    </script>


위와 같이 stopPropagation() 메서드를 자식의 이벤트에 적용시켰을 때, 부모에게 전파되는 버블링 단계를 전파되지 않도록 방지하는 방법이다. 그러나 stopPropagation 메서드를 사용하는 것은 좋지 않은 방법이다. 왜냐하면 다른 이벤트가 어떤 특별한 기능을 수행할 수 있는데, 본인의 이벤트만 처리하고 다른 이벤트를 수행하는 것들을 다 취소해버리는 방법이기 때문에 위험한 방법이다. 혹여나 프로젝트 규모가 커지면 이것 때문에 예상하지 못한 오류가 발생되어서 디버깅을 오랫동안 할 수 있을 것이다. 그러므로 웬만하면 쓰지 않는 것이 좋다.

2. stopPropagation 대신, target과 currentTarget을 비교하자.

  • 부모에서 이벤트에 있는 target과 currentTarget이 똑같지 않으면 return을 해준다.
    ( 부모는 target과 currentTarget이 다르기 때문에 더 이상 처리되지 않는다. )
    <div>
      <span>Click</span>
    </div>
    
    <script>
      const parent = document.querySelector('div');
      const children = document.querySelector('span');

      parent.addEventListener('click', e => {   
        console.log(e.target);
        console.log(e.currentTarget);
        
        if (e.target !== e.currentTarget) {
          return;
        }
        console.log('부모 event');
      });
      
      children.addEventListener('click', e => {
        console.log('자식 event');
      });
    </script>

profile
꾸준히 새로운 것을 알아가는 것을 좋아합니다.

0개의 댓글