ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Event Capture, Propagation, Bubbling and Once
    Web/JS30 2020. 12. 24. 22:24
    반응형

    오늘은 이벤트 캡쳐와 버블링 등 자바스크립트의 이벤트를 다루기 위해서는

    필수적으로 알아야 할 이론들에 관한 내용을 가르쳐주는 예제이다.

     

    다른 것들은 이미 알고 있었지만 복습하는 데에 의미가 있었고, capture이나 once 같은 옵션들은

    새로 배운 내용이어서 나중에 꽤나 유용하게 써먹을 수 있을 듯 하다.

     


    이벤트 버블링(Event Bubbling)

    우리가 자바스크립트의 특정 요소에 클릭을 하게 되면,

    당연히 해당 요소에서만 이벤트가 발생할 것 같지만 사실은 그렇지 않다.

     

    특정 요소에 클릭을 하게 되면, 해당 요소에서 이벤트가 발생하는 것은 물론이고

    그 요소의 부모 요소, 그 부모의 부모 요소, 이런 식으로 쭉쭉 타고 올라가면서 이벤트가 전달이 된다.

     

    위의 사진에서, 맨 안쪽의 div에는 three라는 클래스가 달려있고, 그 바깥쪽의 div에는 two,

    맨 바깥의 연보라색 div에는 one이라는 클래스가 달려있다.

    const divs = document.querySelectorAll('div');
    
    function logText(e) {
      console.log(this.classList.value);
    }
    
    divs.forEach(div => div.addEventListener('click', logText));

    위의 코드를 실행시키면 콘솔창에는 다음과 같은 결과가 출력된다.

     

    맨 아래에 three, 그 위에 two, 그 위에 one 클래스를 가진 div가 차례차례로 쌓여있고

    특정 div에서 발생한 이벤트가 물방울처럼 위로 타고 올라가면서 전달된다고 생각하면 된다.

    그래서 이 현상의 이름도 'Event Bubbling'이다.

     

    참고로 div끼리만 일어나는 게 아니고, 문서의 최상층까지 계속해서 타고 올라간다.

    하지만 여기서는 세 개의 div들에만 이벤트 리스너를 달아놨기 때문에

    그 위에 위치한 요소들까지 전달된 이벤트는 감지되지 않는다.


    이벤트 캡쳐(Event Capture)

    이벤트 발생이 브라우저에서 동작하는 원리는 다음과 같다.

    맨 처음에 three를 클릭하면, 우선 클릭을 감지(capture) 해야한다. 

    이 때, 맨 위(one)에서부터 아래(three)로 내려가면서 차례차례 클릭을 captrue한다.

    (one => two => three 순으로)

    아직 이벤트는 발생하지 않았고, 클릭을 감지하기만 한 상태이다.

    각 div는 클릭이 발생했다는 정보를 저장해놓는다.

     

    그 후에, 이번에는 반대로 맨 아래에서부터 차례차례 올라가면서 이벤트를 발생시킨다.

    three => two => one 순으로 올라가면서 이벤트를 발생시킨다.


    캡쳐 옵션(Options: Catpure)

    addEventListener 함수에 보면 세 번째 인자가 있다는 사실을 알 수 있을텐데,

    여기에는 '옵션'에 대한 정보를 담은 객체가 들어갈 수 있다.

    그 중 하나가 'capture'에 관한 옵션인데, 만약 우리가 다음과 같이 이벤트 리스너를 작성했다고 해보자.

    divs.forEach(div => div.addEventListener('click', logText, { capture : true }));

    이렇게 하면, 기본값인 'Event Bubbling'이 아니라

    (capture 옵션의 기본값은 false, 즉 bubbling이다.)

    'Event Capturing' 방식으로 이벤트를 발생시키겠다는 의미가 된다.

     

    즉, 앞에서 capturing이 위에서 아래로 내려가면서 발생한다고 했던 것처럼,

    아래에서 위로 올라가면서 이벤트가 발생하는 bubbling이 아니라

    위에서 아래로 내려가면서 capturing과 같은 방식으로 이벤트가 발생하게끔 한다는 뜻이다.

     

    그러면 출력 결과도 아까와는 반대의 순서로 나타나게 된다.

     


    event.stopPropagation

    function logText(e) {
      console.log(this.classList.value);
      e.stopPropagation();
    }

     

    'Stop propagation'은 곧 'Stop bubbling'과 동일한 의미라고 생각하면 된다.

    이벤트가 차례차례 위로 올라가면서 부모에까지 이벤트 발생시키는 것을 멈춘다는 의미이다.

    정확하게 이벤트가 처음 발생한 그 자리에서만 이벤트가 발생하도록 한다.

     

    아래의 사진은 맨 안쪽의 div를 클릭한 결과인데, 이벤트가 버블링되지 않는다는 사실을 알 수 있다.

     


    그러면, captrue 옵션을 줌과 동시에 e.stopPropagation을 달아주면 어떤 식으로 동작할까?

    function logText(e) {
      console.log(this.classList.value);
      e.stopPropagation();
    }
    
    divs.forEach(div => div.addEventListener('click', logText, { capture: true }));

    간단하다. 이벤트가 위에서부터 발생해서 아래로 전달되는데, 이벤트 전달을 하지 말라고 했기 때문에

    가장 위에 있는 div에서만 이벤트가 발생하고 이후에는 이벤트가 전달되지 않는다.

    그래서, 콘솔창 결과를 보면 'one'만 출력되어 있다는 사실을 확인할 수 있다.

     


    once 옵션(Options: once)

    최근에 브라우저에 새롭게 추가된 옵션 중에 'once'라는 옵션도 있다.

    divs.forEach(div => div.addEventListener('click', logText, { 
      capture: false,
      once: true
    }));

     

    얘는 이벤트 리스너에 달아놓으면, 그 이벤트 리스너는

    단 한 번만 이벤트를 감지하고, 자기를 스스로 unbind해버린다.

     

    즉, 이벤트 리스너가 한 번만 동작하고 removeEventListener를 하는 것과 동일한 효과이다.

     

    실제로 사용될 만한 예를 들어보자면, 결제 버튼을 예로 들 수 있다.

    결제 버튼같은 것들은 처리될 때까지 시간이 걸리는 경우가 많은데

    답답하다고 여러 번 누르면 큰일날 수가 있다.

    그래서 한 번만 동작하도록 하기 위해서 once 옵션을 사용해주면

    여러번 중복 결제 되는 위험을 사전에 예방할 수가 있게 된다.

    반응형

    'Web > JS30' 카테고리의 다른 글

    Click and Drag to Scroll  (0) 2020.12.26
    Stripe Follow Along Nav  (0) 2020.12.26
    Sticky Nav 🩹  (0) 2020.12.23
    📢 Speech Synthesis 🔊  (0) 2020.12.23
    Following Along Links  (0) 2020.11.29

    댓글

Designed by Tistory.