[JS] 이벤트 버블링 / 캡쳐링 / 위임

2021. 11. 30. 11:08Javascript/개념

1.이벤트와 이벤트 핸들링

자바 스크립트의 대부분의 코드는 이벤트(event)에 의해 동작된다.

이벤트란 클릭이라던가 키 입력 같이 사용자가 행하는 모든 동작을 의미하는데,

이러한 이벤트가 발생했을 때 이에 맞는 상황을 지정해주고 처리하는 것을 이벤트 핸들링이라 한다.

 

element.addEventListener(event, function, useCapture)

 

위처럼 addEventListener()를 사용할 때,

세 번째 인자인 useCapture와 관련된 개념이 바로 이벤트 버블링(Bubbling)과 캡쳐링(Capturing)이다.

default 값은 false (버블링)이며, true로 변경 시 캡쳐링을 통해 이벤트를 전파한다. 

 

 

 

 

2. 이벤트 버블링

이벤트 버블링은 특정 화면 요소에서 이벤트가 발생했을 때 해당 이벤트가 더 상위의 요소들로 전달되어 가는 특성을 의미한다.

쉽게 말하자면 HTML은 기본적으로 트리 구조를 갖는데 트리 구조상 더 위에 위치한 것이 상위 요소 이므로

하위요소 즉, 자식 요소에서 발생한 이벤트가 상위의 부모 요소에 까지 영향을 미치는 것을 의미한다.

 

<body>
  <div class="one">
    <button>one</button>
    <div class="two">
      <button>two</button>
      <div class="three">
        <button>three</button>
      </div>
    </div>
  </div>

<script>

  const divs = document.querySelectorAll("div");
  divs.forEach((div) => {
    div.addEventListener("click", () => console.log(div.className));
  });

</script>
</body>

우린 여기서 한가지 의문을 가질 수 있다.

어째서 'three'버튼을 클릭하면 'three, two, one' 모두가 출력되는 걸까?

그 이유는 브라우저가 이벤트를 이벤트 버블링 방식으로 감지했기 때문이다.

이벤트 버블링은 특정 요소에서 이벤트 발생 시 해당 이벤트를 최 상위에 있는 요소까지 전파 시키는 방식이다.

따라서 'three'버튼 클릭 시 'three' ⇒ 'two' ⇒ 'one' 순으로 클릭 이벤트가 동작하며,

같은 이유로 'two' 버튼 클릭 시 'two' ⇒ 'one' 으로 클릭 이벤트가 전파되는 것이다 .

 

 

 

3. 이벤트 캡쳐링

이벤트 캡쳐링이란 이벤트 버블링과는 반대로 상위요소에서 하위요소로의 이벤트 전파방식을 의미한다.
특정 이벤트가 발생했을 때 최상위 요소인 body 태그에서 부터 해당 태그를 찾아 내려간다.

<body>
  <div class="one">
    <button>one</button>
    <div class="two">
      <button>two</button>
      <div class="three">
        <button>three</button>
      </div>
    </div>
  </div>

<script>
  const divs = document.querySelectorAll("div");
  divs.forEach((div) => {
    div.addEventListener("click", () => console.log(div.className), true);
  }); //addEventListener()의 세번째 인자로 true를 주었다. 기본값은 false(버블링)이다.
  
</script>
</body>

이벤트 버블링과 비슷한 결과지만, 이벤트 버블링과는 반대로 위에서부터 아래로 전파되는 방식이기에,

'three' ⇒ 'two' ⇒ 'one'이 아닌, 'one' ⇒ 'two' ⇒ 'three' 순으로 출력되게된다.

 

 

4. 이벤트 위임(Event Delegation)

<body>
  <ul class="lists">
    <li class="1">list1</li>
    <li class="2">list2</li>
    <li class="3">list3</li>
    <li class="4">list4</li>
  </ul>
</body>
<script>
  const ul = document.querySelector('.lists')
  ul.addEventListener('click', event => {
    console.log(event.target)
  })
</script>

만일 <ul>태그가 상위 요소이고, 하위 요소들로 <li>태그들이 있다고 생각해보자.

그리고 각 <li>태그들을 눌렀을 때 각 요소들에 각각의 이벤트를 부여하고 싶다면

일일이 addEventListener를 부여하는 방법이 있지만, 이는 너무 비효율이며,

특정 상황에서 <li>태그가 새로 생겨야 하는 상황이라면 이를 처리할 방법은 더더욱 복잡해진다.

그러나 이런 상황에서 이벤트 버블링의 특성을 활용하면 효율적인 이벤트 처리가 가능해진다.

 

위 예제처럼 상위 요소인 <ul>태그에 이벤트 리스너를 등록해주면

하위요소에서 발생한 이벤트가 위로 전파되는 이벤트 버블링 특성에 의해

다른 <li>태그들이 생겨도 정상적으로 이벤트 핸들링을 할 수 있다. 그리고 이를 이벤트 위임이라 한다.

 

 

 

 

새로 추가된 리스트 아이템(이벤트 위임 학습)에서 클릭 이벤트가 동작하지 않는 모습


<body>
<h1>오늘의 할 일</h1>
<ul class="itemList">
    <li>
        <input type="checkbox" id="item1">
        <label for="item1">이벤트 버블링 학습</label>
    </li>
    <li>
        <input type="checkbox" id="item2">
        <label for="item2">이벤트 캡쳐 학습</label>
    </li>
</ul>

<script>

    const inputs = document.querySelectorAll('input');
    inputs.forEach( input => {
        input.addEventListener('click', () => {
            alert('clicked')
        })
    })

    // 새 리스트 아이템 추가하는 코드
    const itemList = document.querySelector('.itemList')

    const li = document.createElement('li')
    const input = document.createElement('input')
    const label = document.createElement('label')
    const labelText = document.createTextNode('추가된 아이템 리스트')


    input.setAttribute('type', 'checkbox')
    input.setAttribute('id', 'item3')
    label.setAttribute('for', 'item3')

    label.appendChild(labelText)

    li.appendChild(input)
    li.appendChild(label)
    itemList.appendChild(li)

</script>
</body>

 

 

 

 

 

const itemList = document.querySelector('.itemList')
 itemList.addEventListener('click', () => {
   alert('clicked')
})

리스트 아이템이 많아지면 많아질수록 이벤트 리스너를 다는 작업 자체가 매우 번거롭다.

이 번거로운 작업을 해결할 수 있는 방법이 바로 이벤트 위임(Event Delegation)이다.

 

 

 

5. 이벤트 위임을 막고 싶을 때

event.stopPropagation()

위 API는 해당 이벤트가 전파되는 것을 막는다.

이벤트 버블링의 경우에는 클릭한 요소의 이벤트만 발생시키고 상위 요소로 이벤트를 전달하는 것을 방해한다.

그리고 이벤트 캡쳐의 경우에는 클릭한 요소의 최상위 요소의 이벤트만 동작시키고 하위 요소들로 이벤트를 전달하지 않음.

 

 

 

'Javascript > 개념' 카테고리의 다른 글

[JS] Filter()  (0) 2021.12.15
[JS] 마우스 이벤트 종류  (0) 2021.12.10
[JS] 깊은복사 / 얕은복사  (0) 2021.11.30
[JS] 원시타입 / 참조타입 (객체,배열비교)  (0) 2021.11.30
[JS] 배열 메소드  (0) 2021.11.16