본문 바로가기
프로그래밍/JavaScript

[JavaScript] 이벤트(Event) 관리

by tempus 2021. 7. 20.
반응형

이번에는 Vanilla JS에서 Event를 어떻게 등록하고 감지하여 그 이벤트를 어떻게 다른 화면 요소에 전파하는지를 공부하여 정리하였습니다. Vanilla JS에서 이벤트를 전달하는 방식은 Event Bubbling , Event Capture, Event Delegation로 크게 3가지가 있습니다.

 

🔶 Vanilla JS에서 Event 사용법

 Vanilla JS에서 Event를 등록하여 사용하는 방법은 아래와 같습니다.

<button class ="btn">item button</button>
const btn = document.querySelector(".btn"); 

btn.addEventListener("click" , event=>{
console.log("doing something"); 
}); 

//addEventListener(A , B) -> A라는 event가 일어났을 때 B라는 함수를 실행한다.

🔶 Event Bubbling

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

예를 들면 아래와 같습니다.

<div class="big"> Big! 
    <div class="middle"> Middle! 
        <div class="small"> Small! 
        </div> 
    </div> 
</div>
const divs = document.querySelectorAll('div'); 
divs.forEach(function(div) { div.addEventListener('click', e =>{ 
console.log(event.currentTarget.className);
}); 
});

위와 같이 코드를 작성하고 <div class="small"></div>을 누르게 되면 아래와 같은 결과가 나옵니다.

event_bubbling_img


보시다시피 small->middle->big으로 이벤트가 전달되는 것을 알 수 있습니다. 대부분의 이벤트는 버블링이 됩니다. 만약 상위 요소에 이벤트가 등록이 되어있지 않다면 확인할 수 없습니다. 이러한 버블링을 제한하려면 event.stopPropagtaion()을 사용하면 됩니다. 주의할 점은 꼭 필요한 상황이 아니면 쓰지 말아야 합니다.

function logEvent(event) { event.stopPropagation(); }

🔶 Event Capture

특정한 화면 요소에서 이벤트가 발생했을 때 버블링과는 반대로 해당 이벤트가 전달되어 가는 특성

<div class="big"> Big! 
    <div class="middle"> Middle! 
        <div class="small"> Small! 
        </div> 
    </div> 
</div>

 

const divs = document.querySelectorAll('div'); 
divs.forEach(function(div) { div.addEventListener('click', logEvent, { 
capture: true // default 값은 false 
}); 
}); 
function logEvent(event) { console.log(event.currentTarget.className); }

위와 같이 코드를 작성하고 <div class="small"></div>을 누르게 되면 아래와 같은 결과가 나옵니다.

event_capture_img

big-> middle -> small 으로 이벤트가 전달되는 것을 알 수 있습니다. 여기서도 만약 원하는 이벤트만 신경 쓰고 싶다면 event.stopPropagtaion()을 사용하면 됩니다.


🔶 Event Target

event.target은 이벤트가 발생했을 때 가장 안쪽 요소를 의미합니다. 위에서는 우리가 실제로 클릭한 <div class="small"></div>가 target이 될 것입니다. 하지만 여기서 주의할 점은 event.target 과 event.currentTarget(=this)은 다르다는 것입니다. this는 현재 요소로, 현재 실행 중인 핸들러가 할당된 요소를 참조합니다. (이벤트가 바인딩된 요소를 반환)

<div class="big"> Big! 
   <h1 class="middle"> Middle! 
     <p class="small"> Small! 
     </p> 
   </h1> 
</div>
const divs = document.querySelector('div'); 
divs.addEventListener('click', logEvent); 
function logEvent(event) { console.log("target = " + event.target.tagName + ", this=" + this.tagName) }

여기서 <p> 태그를 누르면 event.target.tagName : p이고 this.tagName : div가 됩니다.


🔶 Event Delegation

Vanilla JS로 웹 앱을 구현할 때 자주 사용하게 되는 코딩 패턴입니다. 이벤트 위임은 하위 요소에 각각 이벤트를 붙이지 않고 상위 요소에서 하위 요소의 이벤트를 제어하는 방식입니다.

<h1>To Do</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>

위와 같은 html 파일이 있고 아래와 같은 이벤트를 input 태그에 등록을 하였다고 가정했을 때

//Event 1 
var inputs = document.querySelectorAll('input'); 
inputs.forEach(function(input) { 
    input.addEventListener('click', function() {
        alert('clicked');
     }); 
 });

여기서 새로운 <li>을 추가하고 눌러보면 이벤트가 작동하지 않습니다.

// 새 리스트 아이템을 추가하는 코드 
var itemList = document.querySelector('.itemList'); 
var li = document.createElement('li'); 
var input = document.createElement('input'); 
var label = document.createElement('label'); 
var 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);

왜냐하면 이미 이벤트 리스너를 추가하는 시점에 아이템은 2개이고 따라서 새롭게 추가된 리스트에는 이벤트 리스너가 적용되지 않습니다. 그렇다면 이러한 문제를 해결하기 위해서는 어떻게 해야 하는가? 이때 사용하는 것이 이벤트 위임입니다. 아래와 같이 변경하면 상위 태그인 <ul>에 이벤트를 달아놓고 하위에 있는 이벤트를 감지하게 합니다.

//앞서 이벤트 리스너를 다음과 같이 변경 
var itemList = document.querySelector('.itemList');
itemList.addEventListener('click', function(event) { alert('clicked'); });

 

반응형

'프로그래밍 > JavaScript' 카테고리의 다른 글

[JavaScript] 비동기 처리를 위한 Promise  (0) 2021.07.29

댓글


loading