-
모던 자바스크립트 Deep Dive - 이벤트 전파와 이벤트 위임 , preventDefault , stopPropagationJavaScript 2021. 9. 26. 01:12
[ 이벤트 전파 ]
DOM 트리 상에 존재하는 DOM 요소 노드에서 발생한 이벤트는 DOM 트리를 통해 전파된다.
이벤트 캡처링 : 이벤트가 상위요소 -> 하위 요소 전파 ( 화면 캡처는 자기 자신 화면에서 크기가 줄어들 수 있으나 커질 수는 없다. )
이벤트 버블링 : 이벤트가 하위요소 -> 상위 요소 전파 ( 거품은 커진다. )
// html ... <ul id = "fruits"> <li id = "apple">apple</li> <li id = "banana">banana</li> <li id = "orange">orange</li> </ul>
위와 같은 html이 있다.
<script> 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) </script>
위 코드의 banana를 클릭했을 때의 실행 결과를 유추 해보자.
2 <li id = "banana">banana</li> <li id = "banana">banana</li> 3 <li id = "banana">banana</li> <ul id = "fruits">...</ul>
banana를 먼저 event등록을 해주었으니 먼저 실행되겠지? 하면 아니다.
결과는
1 <li id = "banana">banana</li> <ul id = "fruits">...</ul> 2 <li id = "banana">banana</li> <li id = "banana">banana</li>
이다.
$fruit의 addEventListener로 세 번째 인수에 true를 넣었기 때문에
이벤트 캡처링을 허가해준 것이다.
따라서, 이벤트 순서를 window에서부터 내려온 것이다.
즉, window -> ... -> ul -> li 순서로 이벤트 핸들러가 호출되는 것이다.<script> 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) </script>
그렇다면, 위 코드에서 banana를 클릭했을 때 출력 결과를 예상할 수 있을 것이다.
1 <li id = "banana">banana</li> <ul id = "fruits">...</ul> 2 <li id = "banana">banana</li> <li id = "banana">banana</li> 3 <li id = "banana">banana</li> <ul id = "fruits">...</ul>
즉, 이벤트는 window -> ... -> ul -> li -> ul -> ... -> window 순서로 전파가된다.
여기서 캡처링을 true하냐 마냐의 선택도 중요하다.[ 이벤트 위임 ]
... <ul id = 'fruits'> <li id = "apple">apple</li> <li id = "banana">banana</li> <li id = "orange">orange</li> </ul> ...
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 요소 이후로 이벤트 전파가 중지된다.'JavaScript' 카테고리의 다른 글
모던 자바스크립트 Deep Dive - 이벤트 핸들러 등록과 제거 (0) 2021.09.26 모던 자바스크립트 Deep Dive - 프로퍼티 섀도잉 , 교체 , 정적 프로퍼티 (0) 2021.09.23 모던 자바스크립트 Deep Dive - 프로토타입 체인 (0) 2021.09.23 모던 자바스크립트 Deep Dive - 프로토타입 생성 (0) 2021.09.23 모던 자바스크립트 Deep dive - 프로토타입 ( 리터럴 표기법 ) (0) 2021.09.23