[Javascript] 이벤트 전파

youngseo·2022년 2월 19일
1

Javascript

목록 보기
25/46
post-thumbnail

이벤트 전파

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

아래 사이트를 이용해 조금 더 쉽게 익힐 수 있겠습니다.

DOM EVENT

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

이번 포스팅에서는 이벤트 전파 방법인 CaptureBubble에 대해 살펴보도록 하겠습니다.

1. 이벤트 버블링

버블링은 표현 그대로 거품처럼 위로 올라간다라고 생각을 할 수 있습니다. 즉 이벤트가 하위요소에서 발생했을 때 하위요소에서 상위요소로 계속 전파가 되게 되는 것입니다.

예시를 통해 공부해보도록 하겠습니다.

  <article>
    ARTICLE
    <div>
      DIV
      <p>
        P
        <br />
        <button>BUTTON</button>
      </p>
    </div>
  </article>
  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'))

버튼을 클릭하면 버튼 -> 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>
  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'
  })


실습을 해보면 하위요소를 클릭하면 콘솔창에 'UL 이벤트 발생'라는 warn이 출력된 후 'div에 이벤트 발생'라는 에러가 뜨며 이벤트 버블링이 일어나고 있는 것을 활인할 수 있습니다.

이 단계에서 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: false
  })

3. 이벤트 위임

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

예시를 통해 알아보도록 하겠습니다.



만약 list를 클릭했을 때 이벤트가 발생을 하게 하려면, 어디에 이벤트를 달아야할까요?

이벤트를 다루는데 익숙하지 못한 경우 querySelectorAll을 통해 모든li를 가지고와 이벤트를 다루려고 할 수도 있습니다.

const items = document.querySelectorAll('li')

items.forEach((item)  => item.addEvntListener('click', console.log)


하지만 이 경우 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를 이용해 분기를 할 수 있습니다. liclass="item"을 정의한 후 예제를 작성 해보도록 하겠습니다.

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

  items.addEventListener('click', (event) => {
    const [item] = event.target.classList;
    //cont item = event.target.classList[0]과 같습니다.

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

이렇게 classListitem이 있는 경우에만 실행을 하게 할 수 있습니다.

마무리하며

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

0개의 댓글