티스토리 뷰

HTML 태그는 중첩되어 있다. 따라서 태그에서 발생하는 이벤트는 중첩되어 있는 태그들 모두가 대상이 될 수 있다.

이런 경우 중첩된 태그들에 이벤트가 등록되어 있다면 어떻게 처리될까?

ref: https://opentutorials.org/course/1375/6768 [생활코딩]

  • 캡쳐링(capturing) - 이벤트가 부모에서부터 발생해서 자식으로 전파 
    • 밖에서부터 안쪽으로 이벤트가 전파됨
    • IE 낮은 버전에서는 작동하지 않기 때문에 많이 사용 X 
    • 코드에서 차이점은 document.querySelector('html').addEventListener('click', handler, true);
    • 이벤트리스너의 3번째 인자(use capturing) 
      • 기본값은 false ->3번째 인자를 주지 않는다면 자동으로 버블링 처리
      • 값이 true이면 캡쳐링, false이면 버블링
  • 버블링(bubbling) - 이벤트가 자식에서부터 발생해서 부모로 전파 
    • 안쪽 코어부터 밖으로 버블버블 이벤트가 전파된다해서 버블링 
    • 캡처링 <-> 버블링 두 개념 사이에는 이벤트가 전달되는 흐름에 차이가 있음
    • 실제로 많이 사용되는 것은 버블링이다. 모든 브라우저에서 사용가능하기 때문에

▶버블링 관련 예시코드

<html>
  <head>
    <title>이벤트의 전파 (버블링)</title>
    <style>
      html {
        border: 5px solid red;
        padding: 30px;
      }
      body {
        border: 5px solid green;
        padding: 30px;
      }
      fieldset {
        border: 5px solid blue;
        padding: 30px;
      }
      input {
        border: 5px solid black;
        padding: 30px;
      }
    </style>
  </head>
  <body>
  <fieldset>
      <legend>event propagation</legend>
      <input type="button" id="target" value="target" />
    </fieldset>
     <script>
  function handler(event){
    const phases = ['capturing', 'target', 'bubbling']
    console.log(event.target.nodeName, this.nodeName, phases[event.eventPhase-1]);
}
function stophandler(event){
    const phases = ['capturing', 'target', 'bubbling']
    console.log(event.target.nodeName, this.nodeName, phases[event.eventPhase-1]);
    event.stopPropagation();
}

document.getElementById('target').addEventListener('click', handler, false);
document.querySelector('fieldset').addEventListener('click', handler, false);
document.querySelector('body').addEventListener('click', stophandler, false);
document.querySelector('html').addEventListener('click', handler, false);​
 </script>
  </body>
</html>

버블링 예시코드 결과물

 

event.eventPhase (이벤트 객체의 이벤트페이즈 프로퍼티는 무엇일까)?

  • 정의: Event 인터페이스의 eventPhase 읽기 전용 속성은 현재 평가 중인 이벤트 흐름 단계를 나타낸다. 
  • 반환값: 이벤트 흐름의 단계를 나타내는 정수 값을 반환 
    • Event.NONE (0) //이 이벤트는 현재 처리중이 아님
    • Event.CAPTURING_PHASE (1) // 이벤트 대상의 부모 객체를 통해 전파중
    • Event.AT_TARGET (2) // 이벤트가 이벤트 대상에 도착함 -> Event.bubbles 가 false이면 해당 단계가 끝남과 동시에 이벤트 처리도 마침
    • Event.BUBBLING_PHASE (3) // 이벤트가 대상의 조상을 따라 역순으로 전파중
  • 사용용도: 핸들러가 실행되는 모드(캡쳐링, 버블링, 타겟)가 어떤 것인지 확인하기 위함

 event.stopPropagation()

  • 정의: Event 인터페이스의 stopPropagation() 메서드는 현재 이벤트가 캡처링/버블링 단계에서 더 이상 전파되지 않도록 방지합니다. // 이벤트의 흐름을 중간에 끊어주는 용도로 사용되는 메소드 , JS가 이후에 등장하는 이벤트핸들러에 대한 호출을 끊는다.
  • 주의) 전파를 방지해도 이벤트의 기본 동작은 실행된다 -> 링크나 버튼의 클릭을 막는 것은 아닙니다. 이런 기본동작을 방지하려면 event.preventDefault()메소드를 사용하세요.

*propagation [n. (소리 등의)전파, 전달]

function stophandler(event){
    const phases = ['capturing', 'target', 'bubbling']
    console.log(event.target.nodeName, this.nodeName, phases[event.eventPhase-1]);
    event.stopPropagation();
}

document.getElementById('target').addEventListener('click', handler, false);
document.querySelector('fieldset').addEventListener('click', handler, false);
// 2번째 인자로 위에 새로 추가한 stophandler 함수를 넣어준다. 
// 해당 함수에는 stopPropagation()메소드가 들어있다. -> 이 메소드는 이후의 이벤트 전파를 막는다.
document.querySelector('body').addEventListener('click', stophandler, false);
document.querySelector('html').addEventListener('click', handler, false);​

stopPropagation() 예시코드 결과물

->HTML 가 나오지 않았다. body 태그를 마지막으로 해서 이벤트의 전파가 끊김 

 

참고로 ie9 이전의 브라우저에서는 이벤트 전파을 막기 위해서 event.cancelBubble 프로퍼티를 사용해야 한다.

 

이벤트 위임

-하위 요소에 각각 이벤트를 붙이지 않고 상위 요소에서 하위 요소의 이벤트를 제어하는 방식(가장 바깥에 있는 부모에 하나만 이벤트를 붙여 해당 이벤트를 자식 요소에 위임하는 것?)

  • 공통 조상에 할당한 핸들러에서 event.target을 통해 실제 어디서 이벤트가 발생했는 지 알 수 있다. 이를 통해 이벤트를 핸들링할 수 있다. 
  • 이벤트 위임은 DOM이벤트에 적용할 수 있는 유용한 패턴 
  • 주로, 유사한 요소에 동일한 핸들러를 적용할 때 주로 사용하지만 이 경우에만 사용하는 것은 아님
  • 많은 핸들러를 할당하지 않아도 되기 때문에 초기화가 단순해지고 메모리 절약됨
  • 코드 짧아짐, innerHTML이나 유사한 기능을 하는 스크립트로 요소 덩어리를 더하거나 뺄 수 있기 때문에 DOM 수정이 쉬워진다. 
  • (단점) 이벤트 위임을 사용하려면 이벤트가 버블링되어야 한다. 하지만 몇몇 이벤트는 버블링되지 않음 낮은 레벨에 할당한 핸들러엔 event.stopPropagation()을 쓸 수 없음

e.g.) 아이템 리스트에 아이템을 새로 추가할 때마다 클릭 이벤트를 새로 생긴 자식요소에 일일이 등록(핸들러 할당)할 필요가 없다. 

캡처링과 버블링을 활용하면 강력한 이벤트 핸들링 패턴인 이벤트 위임을 구현할 수 있다.

 

TIP: 문서 레벨의 핸들러를 만들 땐 항상 addEventListenver 를 사용해라. document.onclick을 사용해선 안된다. 충돌을 일으킬 가능성이 있음 새로운 핸들러가 이전의 핸들러를 덮어쓸 수 있기 때문이다. 

 

 

+버블링과 캡처링 관련 참고자료 사이트

https://joshua1988.github.io/web-development/javascript/event-propagation-delegation/ 

 

이벤트 버블링, 이벤트 캡처 그리고 이벤트 위임까지

(기본) 이벤트 버블링, 이벤트 캡처링, 그리고 이벤트 위임까지 이벤트 전달 방식과 관련된 모든 것을 파헤쳐 봅니다.

joshua1988.github.io

https://javascript.info/bubbling-and-capturing

 

댓글