BoostCource/Front-end

[FE] 03. Event delegation (이벤트 버블링)

칸타탓 2018. 7. 28. 16:12

3. 웹 애플리케이션 개발 - Event delegation

 

 

아래 화면은 가로로 배치된 책 리스트이며 각각 리스트에 클릭을 할 때 어떤 이벤트가 발생해야 한다고 가정해보자.

addEventListener를 사용해서 이벤트 등록을 할 수 있다.

<ul>
  <li>
    <img src="https://images-na.,,,,,/513hgbYgL._AC_SY400_.jpg" class="product-image" > </li>
  <li>
    <img src="https://images-n,,,,,/41HoczB2L._AC_SY400_.jpg" class="product-image" > </li>
  <li>
    <img src="https://images-na.,,,,51AEisFiL._AC_SY400_.jpg" class="product-image" > </li>
 <li>
    <img src="https://images-na,,,,/51JVpV3ZL._AC_SY400_.jpg" class="product-image" >
 </li>
</ul>

위 HTML 코드의 li 각각에 addEventListener를 통해 이벤트를 등록할 수 있다.

아래 코드는 클릭한 지점의 이미지 src가 출력된다.

var log = document.querySelector(".log");
var lists = document.querySelectorAll("ul > li");
 
for(var i=0, len=lists.length; i < len; i++) {
  lists[i].addEventListener("click", function(evt) {
     log.innerHTML = "clicked" + evt.currentTarget.firstElementChild.src;
  });
}
 
브라우저는 4개의 이벤트 리스너를 기억하고 있다.

그런데 list가 훨씬 더 많다면 브라우저는 기억해야 할 이벤트 리스너도 그만큼 많아지므로 비효율적이다.

만약 list가 한 개 더 동적으로 추가된다면 추가된 엘리먼트에 역시 addEventListener를 해줘야 하므로 번거롭다.

이때 target 정보를 사용할 수 있다.

 

좀 더 효율적인 이벤트 등록을 위해 아래처럼 ul 태그에만 이벤트를 새롭게 등록해보자.

ul.addEventListener("click",function(evt) {
    console.log(evt.currentTarget, evt.target);
});

target에는 IMG, currentTarget에는 ul이 출력된다.

이벤트는 ul에 걸었지만 타겟은 클릭한 지점의 정보인 IMG를 알려준다.

 

li 나 img 태그는 ul 태그에 속하기도 하므로 ul에 등록한 이벤트 리스너도 실행이 된다. 이것을 이벤트 버블링이라고 한다.

클릭한 지점이 하위 엘리먼트라고 하여도 그것을 감싸고 있는 상위 엘리먼트까지 올라가면서 이벤트 리스너가 있는지 찾는 과정이다. 

 

만약 img, li, ul에 각각 이벤트를 등록했었다면, 3개의 이벤트 리스너가 실행된다.

아래 이미지는 하위 엘리먼트는 3번부터 이벤트가 발생하고 2,1 순으로 이벤트가 발생했다.

 

 

 

Capturing

Capturing는 반대로 이벤트가 발생하는 것이다. 기본적으로는 Bubbling 순서로 이벤트가 발생한다.

Capturing 단계에서 이벤트 발생을 시키고 싶다면 addEventListener 메서드의 3번째 인자값을 true로 주면 된다.

많이 사용되지는 않는다.

 


* 실습 코드

img나 li를 클릭해도 ul에 이벤트가 발생하고, 이벤트 리스너가 실행된다. img를 클릭하면 ul 그리고 img 태그가 나온다.

ul.addEventListener("click",function(evt) {
    console.log(evt.currentTarget.tagName, evt.target.tagName);
});

 

 

target 정보는 실제 클릭 된 하위 엘리먼트를 알려준다. 이 점을 이용해서 src를 추출할 수 있다.

addEventListener 메서드를 한 번만 쓰면서 모든 list의 image 정보를 확인할 수 있으며 list 태그가 하나 더 추가된다고 하여도 문제없이 동작한다.

var ul = document.querySelector("ul");
ul.addEventListener("click",function(evt) {
    if(evt.target.tagName === "IMG") {
      log.innerHTML = "clicked" + evt.target.src;
    }
});

 

위 첫번째 이미지에서 이미지 태그는 padding 값이 있어서 img 태그와 li 태그 사이에 공백이 존재한다.

이 공백을 클릭하면 tagName이 li라서 위에서 구현한 조건문으로 들어가지 않았기 때문에 img가 출력되지 않는다.

공백을 클릭해도 이미지 url을 출력하기 위해서는 아래와 같이 수정하면 된다.

var ul = document.querySelector("ul");
ul.addEventListener("click",function(evt) {
  debugger;
    if(evt.target.tagName === "IMG") {
      log.innerHTML = "clicked" + evt.target.src;
    } else if (evt.target.tagName === "LI") {
      log.innerHTML = "clicked" + evt.target.firstElementChild.src;
    }
});

 

[전체 코드] 실습코드 바로가기

 

 

'BoostCource > Front-end' 카테고리의 다른 글

[FE] 03. Tab UI  (0) 2018.07.28
[FE] 03. HTML templating  (0) 2018.07.28
[FE] 03. DOMContentLoaded, load  (0) 2018.07.28
[FE] 03. 디렉토리 구성  (0) 2018.07.28
[FE] 03. Web Animation 활용  (0) 2018.07.27