모던 자바스크립트 Deep Dive - 이벤트 전파와 이벤트 위임...

모던 자바스크립트 Deep Dive - 이벤트 전파와 이벤트 위임...

[ 이벤트 전파 ]

DOM 트리 상에 존재하는 DOM 요소 노드에서 발생한 이벤트는 DOM 트리를 통해 전파된다.

이벤트 캡처링 : 이벤트가 상위요소 -> 하위 요소 전파 ( 화면 캡처는 자기 자신 화면에서 크기가 줄어들 수 있으나 커질 수는 없다. )

이벤트 버블링 : 이벤트가 하위요소 -> 상위 요소 전파 ( 거품은 커진다. )

// html ... apple banana orange

위와 같은 html이 있다.

const $fruits = document.querySelector('#fruits'); const $banana = document.querySelector('#banana'); $banana.addEventListener('click', e => { console.log(e.eventPhase) console.log(e.target) console.log(e.currentTarget) }) $fruits.addEventListener('click', e => { console.log(e.eventPhase) console.log(e.target) console.log(e.currentTarget) },true)

위 코드의 banana를 클릭했을 때의 실행 결과를 유추 해보자.

2 banana banana 3 banana ...

banana를 먼저 event등록을 해주었으니 먼저 실행되겠지? 하면 아니다.

결과는

1 banana ... 2 banana banana

이다.

$fruit의 addEventListener로 세 번째 인수에 true를 넣었기 때문에

이벤트 캡처링을 허가해준 것이다.

따라서, 이벤트 순서를 window에서부터 내려온 것이다.

즉, window -> ... -> ul -> li 순서로 이벤트 핸들러가 호출되는 것이다.

const $fruits = document.querySelector('#fruits'); const $banana = document.querySelector('#banana'); $fruits.addEventListener('click', e => { console.log(e.eventPhase) console.log(e.target) console.log(e.currentTarget) }) $banana.addEventListener('click', e => { console.log(e.eventPhase) console.log(e.target) console.log(e.currentTarget) }) $fruits.addEventListener('click', e => { console.log(e.eventPhase) console.log(e.target) console.log(e.currentTarget) },true)

그렇다면, 위 코드에서 banana를 클릭했을 때 출력 결과를 예상할 수 있을 것이다.

1 banana ... 2 banana banana 3 banana ...

즉, 이벤트는 window -> ... -> ul -> li -> ul -> ... -> window 순서로 전파가된다.

여기서 캡처링을 true하냐 마냐의 선택도 중요하다.

[ 이벤트 위임 ]

... apple banana orange ...

const $fruits = document.querySelector('#fruits'); const $apple = document.querySelector('#apple'); const $banana = document.querySelector('#banana'); const $orange = document.querySelector('#orange'); function ativate({target}){ target.classList.toggle('active'); } $apple.onclick = ativate; $banana.onclick = ativate; $orange.onclick = ativate;

위와 같은 방식으로 모든 li에 ativate 이벤트를 넣어주었다.

보기에는 아무런 문제가 없다.

하지만, li 아이템이 100개 혹은 1000개 그 이상이라면?

이것은 DOM 요소에 이벤트 핸들러를 등록하므로 성능 저하의 원인이며 유지보수에도 적합하지 않은 코드이다.

const $fruits = document.querySelector('#fruits'); function activate({target}){ //target이 fruits의 li가 아니면 나간다. if(!target.matches('#fruits > li')) return; [...$fruits.children].forEach($fruit => { $fruit.classList.toggle('active',$fruit === target); }) });

위의 코드 처럼 상위 DOM 요소에 event를 처리해주면 하위 DOM 요소들 판별 코드를 작성만 해주면 문제 없이 간결하게 코드를 작성할 수 있다.

[ preventDefault ]

preventDefault 메서드는 DOM 요소의 기본 동작을 중단 시킨다.

기본 동작 : a 요소를 클릭하면 href 어트리뷰트에 지정된 링크로 이동 , checkbox 또는 radio 요소 클릭 등등...

[ stopPropagation ]

이벤트 객체의 stopPropagation 메서드는 이벤트 전파를 중지 시킨다.

stopPropagation 메서드를 사용한 DOM 요소 이후로 이벤트 전파가 중지된다.

from http://jin-pro.tistory.com/102 by ccl(A) rewrite - 2021-09-26 01:27:24