[Web] Event Delegation

Event Delegation

이벤트 위임. 자식 노드에서 실행시켜야 할 이벤트를 부모에 위임시켜서 자식이 늘어나도 이벤트를 추가하지 않아도 실행 시킬 수 있다. 매우 효율적으로 이벤트를 관리할 수 있는 기능이다. 

사진을 누를 때마다 이벤트가 동작 되게 하려면 어떻게 해야 할까? 자바스크립트 코드의 for문을 이용하여 EventListener를 추가하여 구현 할 수 있을 것이다. 다음은 화면에 나와있는 그림 4개를 클릭할 때마다 이미지의 src를 출력하는 코드이다. 

'event.html'
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Event delegation</title>
    <link rel="stylesheet" href="css/event.css">
</head>
<body>
    <ul>
        <li><img src="photo1.jpg" class="myphoto"></li>
        <li><img src="photo2.jpg" class="myphoto"></li>
        <li><img src="photo3.jpg" class="myphoto"></li>
        <li><img src="photo4.jpg" class="myphoto"></li>
    </ul>
    <section class="log"></section>
   
</body>
 <script src="js/event.js"></script>
</html>
cs

'event.js'
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 url is "+evt.currentTarget.firstElementChild.src;
    });
cs

코드를 실행 시켜보면 겉보기엔 잘 동작하는 것 같아 보인다. 하지만 자세히 들여다 보자. 지금 코드엔 사진이 4개 뿐이다. 그리고 브라우저가 저장해야 할 이벤트또한 4개 뿐이다. 하지만 엘리먼트가 계속 늘어난다면? 추가된 엘리먼트에도 addEventListenr를 추가해야 하고 그에 맞춰 브라우저가 기억해야 하는 이벤트도 계속 무한히 늘어나야 할 것이다. 

이것을 좀 더 효율적으로 구현하기 위해 사용할 수 있는 것이 target 정보이다. 지금은 li 각 엘리먼트에 이벤트를 등록하고 있는데 이벤트를 그 바깥에 있는 ul에 걸어보자. 

var log = document.querySelector(".log");
var ul = document.querySelector("ul");
var img = document.querySelector("img");
img.addEventListener("click",function(){
    console.log("img tag clicked");
})
ul.addEventListener("click",function(evt){
    //IMG, UL
    console.log(evt.target.tagName, evt.currentTarget.tagName);
    
})
cs

신기하게 evt.target 은 img 태그가 선택되고 evt.currentTarget은 ul 태그가 선택된다. ul 태그 안의 이미지 요소 하나에만 이벤트를 걸어 놓을 경우 해당 이미지 이벤트와 ul태그 이벤트가 모두 발생한다. 이것을 '이벤트 버블링' 이라고 한다! 

이벤트 버블링
클릭한 지점이 하위엘리먼트라고 해도, 그것을 감싸고 있는 상위 엘리먼트까지 올라가면서 이벤트 리스너가 있는지 찾는 과정이다. 예를 들어 만약 img, li, ul에 각각 이벤트를 등록했다면 3개의 이벤트 리스너가 실행 된다. 

그리고 호출 했을 때 그 순서는 안에서부터 밖으로 차례대로 호출된다. 

비슷하게 Capturing 이라는 것도 있는데 이것은 bubbling 순서와 반대로 이벤트가 발생한다. Capturing을 발생시키고 싶다면, addEventListner메서드의 3번째 인자 값의 default로 false가 지정돼있는 것을 true로 주면 된다. 

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


이벤트 버블링에 대해 아주 잘 정리해두신 블로그다. 헷갈릴 때 종종 들어가서 참고하면 좋을 것 같다!
https://joshua1988.github.io/web-development/javascript/event-propagation-delegation/


No comments:

Powered by Blogger.