이벤트 전파

김기훈·2023년 3월 15일
0

자바스크립트

목록 보기
16/17

자바스크립트의 이벤트는 전파되는 특성을 가지고 있다. 이 전파되는 방식에는 상위요소에서 하위요소로 내려가는 Capture과 하위요소에서 상위요소로 올라가며 전파되는Bubble이 있다.

또한 리액트, 뷰 등의 사용해 개발을 하다보면 이러한 이벤트 버블링, 캡쳐링으로 인해 예상치 못한 장애가 생길 수도 있다.

1. 이벤트 버블링

버블링은 이벤트가 하위요소에서 발생했을 때 하위요소에서 상위요소로 계속 전파가 되게 되는 것이다.

  <article>
    ARTICLE
    <div>
      DIV
      <p>
        P
        <button>BUTTON</button>
      </p>
    </div>
  </article>
  
  
  <script>
    const article = document.querySelector('article')
    const division = document.querySelector('division')
    const paragraph = document.querySelector('paragraph')
    const button = document.querySelector('button')

    article.addEventListener('click', () => window.alert('article'))
    division.addEventListener('click', () => window.alert('division'))
    paragraph.addEventListener('click', () => window.alert('paragraph'))
    button.addEventListener('click', () => window.alert('button'))
  </script>

버튼을 클릭하면 버튼 -> p -> div -> article 순으로 경고창이 뜨는 것을 확인할 수 있다. 이렇게 상위요소에 속한 하위요소를 클릭하는 경우 상위요소까지 타고 올라가며 이벤트 버블링이 일어나게 됩니다.

이 이벤트 버블링을 방지하기 위해서 사용할 수 있는 방법이 있다.

  button.addEventListener('click', (evnet) => {
    event.stopPropagation();
    window.alert('button')
  })

event객체의 메서드인 stopPropagation()을 사용하면 해당 요소의 이벤트버블링을 막을 수 있다.


2. 이벤트 캡쳐링

이벤트 캡쳐링은addEventLstener의 세번째 매개변수의 capture 옵션을 true 로 설정하면 이벤트 버블링과 반대 방향으로 탐색하게 되는데 이렇게 상위요소에서 하위요소까지 내려가는 전파방식을 이벤트 캡쳐링이라고 한다.

 <div>
    <h1>장바구니</h1>
    <ul>
      <li>노트북</li>
      <li>모니터</li>
      <li>책상</li>
      <li>의자</li>
      <li>키보드</li>
      <li>마우스</li>
    </ul>
  </div>
  
  
  <script>
    const container = document.querySelector('div')
    const list = document.querySelector('ul')

    container.addEventListener('click', (e) => {
      console.error('div에 이벤트 발생')
      e.target.style.background = 'blue'
    })

    list.addEventListener('click', (e) => {
      console.warn('UL 이벤트 발생')
      e.target.style.background = 'red'
    })
  </script>

위 코드를 실행해보면 이벤트 버블링이 일어나고 있는 것을 활인할 수 있다.

이 단계에서 addEvnetLister의 세번째 매개변수의 Capture 옵션을 활용하면 이벤트 캡쳐링을 확인할 수 있다. 이 옵션은 boolean으로 값을 넘기며 기본 값이 false이기 때문에 true값을 넣어 확인을 해보도록 하겠다.

  container.addEventListener('click', (e) => {
    console.error('div에 이벤트 발생')
    e.target.style.background = 'blue'
  }, true)

하위요소를 클릭한 후 상위요소에 관련한 이벤트가 먼저 출력된 후 하위요소의 이벤트가 출력되며 상위요소에서 하위요소로 이벤트가 전파되고 있는 것을 확인할 수 있다.

또한 Capture 옵션을 객체 형태로 작성할 수도 있다.

  container.addEventListener('click', (e) => {
    console.error('div에 이벤트 발생')
    e.target.style.background = 'blue'
  },{
    capture: true
  })

3. 이벤트 위임

이벤트 위임이란 하위 요소마다 이벤트를 붙이지 않고 상위 요소에서 하위 요소의 이벤트들을 제어하는 방식을 말하다.

만약 list를 클릭했을 때 이벤트가 발생을 하게 하려면, 어디에 이벤트를 달아야할까? 이벤트를 다루는데 익숙하지 못한 경우 querySelectorAll을 통해 모든 li를 가지고와 이벤트를 다루려고 할 수도 있다.

하지만 이 경우 li가 많아지게 되면 그만큼 EventListener이 많이 달리며 메모리 낭비가 된다.

이러한 경우를 줄이기 위해 이벤트 위임이라는 방법을 이용할 수 있다. 이벤트 위임에는 class, nodeName을 이용하는 등 다양한 방법이 있다.

nodeName을 사용해 예시를 작성해보도록 하겠다.

  const items = document.querySelector('ul');

  items.addEventListener('click', (event) => {
    if(event.target.nodeName === "LI"){
      alert('LI Click');
    } else {
      alert('No LI Click')
    }
  })

list를 클릭 했을 경우 알림창에 'LI Click'가 list가 아닌 부분을 클릭한 경우 알림창에 'No LI Click'가 출력되는 것을 확인할 수 있다.

또한 이렇게 이벤트 위임을 활용하면 코드를 재활용해 간단하게 작동을 바꿔볼 수도 있다.

  const items = document.querySelector('ul');

  items.addEventListener('click', (event) => {
    if (event.target.nodeName === "LI") {
      event.target.style.background = 'blue';
    }
  })

또한 class를 이용할 수도 있는데 만약 li의 class를 'item' 이라고 했을 경우

  const items = document.querySelector('ul');

  items.addEventListener('click', (event) => {
  
    const item = event.target.classList[0];

    if(item==='item'){
      event.target.style.background = 'blue';
    }
  })

이렇게 classList에 item이 있는 경우에만 실행을 하게 할 수 있다.

이렇게 이벤트 위임을 사용하는 경우 각 요소마다 이벤트를 달지 않아도 되고, 재활용이 가능하기에 효율적으로 활용을 할 수 있다.

profile
평생 공부하기

0개의 댓글

관련 채용 정보