본문 바로가기

JavaScript

[JS] Event flow - capturing과 bubbling

728x90
반응형

Event flow

 

이벤트가 발생하면 capturing phase -> target phase -> bubbling phase 순으로 이벤트를 감지한다.

 

 

 

 

<div class="outer">
    <div class="middle">
        <button>Click Me</button> 
    </div>
</div>

 

const outer = document.querySelector('.outer');
const middle = document.querySelector('.middle');
const button = document.querySelector('button');

outer.addEventListener('click', event => {
    console.log(`outer: ${event.currentTarget}, ${event.target}`);
});
// outer: [objectHTMLDivElement], [object HTMLButtonElement] 

middle.addEventListener('click', event => {
    console.log(`middle ${event.currentTarget}, ${event.target}`);
});
// middle: [objectHTMLDivElement], [object HTMLButtonElement] 

button.addEventListener('click', event => {
    console.log(`button1 ${event.currentTarget}, ${event.target}`);
});
// button: [objectHTMLButtonElement], [object HTMLButtonElement] 

 

outer box 안에 middle box가 있고, middle box 안에 button이 있다.

3가지 요소에 각각 click event가 걸려있다.

button을 click하면 button -> middle -> outer 순으로 3가지 요소에서 모두 이벤트가 발생한다.

 

button을 누르면 부모요소에서 부터 button까지 event가 전달되고(capturing phase )

button에 등록된 event handler가 호출된다.(target phase)

그 다음 부모요소에 등록된 event handler를 호출하게 된다.(bubbling phase )

보통 capturing 단계에서 event를 처리하는 일은 흔하지 않다.

 

target.addEventListener(type, listener, [useCapture]);

 

event handler의 useCapture의 기본값은 false이다.

그래서 따로 지정을 해주지 않는 이상 capturing 단계에서는 event가 일어나지 않는다.

 

button은 event.currentTarget과 event.target이 동일하다.

하지만 outer와 middle은 event.currentTarget과 event.target이 다른 요소를 나타낸다.

 

event.currentTarget : 이벤트가 걸려있는 해당 요소를 리턴한다.

event.target : 이벤트가 발생한 요소, 사용자 클릭한 요소를 리턴한다.

 

outer과 middle의 event.currentTarget은 해당 요소인 div를 가리키고,

outer과 middle의 event.target은 이벤트를 발생시킨 button을 가리킨다.

 

 

 


내가 원하는 eventListener만 실행되도록 하려면 어떻게 해야할까?

 

stopPropagation(), stopImmediatePropagation()을 쓸 수도 있지만

위험하고 예상하지 못한 오류가 발생할 수 있으므로 가능하면 사용하지 않는 것이 좋다.

 

그러면??

조건이 만족할 때만 이벤트를 실행하도록 처리하면 된다.

즉, 부모 요소에서 event.currentTarget과 event.target이 동일하지 않으면

리턴을 해서 그 이벤트를 종료시킨다.

그러면 button을 클릭 했을 때는 button에 걸려있는 event만 실행된다.

 

const outer = document.querySelector('.outer');
const middle = document.querySelector('.middle');
const button = document.querySelector('button');

outer.addEventListener('click', event => {
    if (event.target !== event.currentTarget) {
        return;
    }
    console.log(`outer: ${event.currentTarget}, ${event.target}`);
});
// 실행되지 않음

middle.addEventListener('click', event => {
    if (event.target !== event.currentTarget) {
          return;
    }
    console.log(`middle ${event.currentTarget}, ${event.target}`);
});
// 실행되지 않음

button.addEventListener('click', event => {
    console.log(`button1 ${event.currentTarget}, ${event.target}`);
});
// button: [objectHTMLButtonElement], [object HTMLButtonElement] 

 

 

 

728x90
반응형