0. 작성이유
-
누군가 물어봤는데.. 대답을 잘하지 못했다.
-
stopImmediatePropagation의 역할에 대해서 궁금했다.
-
예제 HTML
<div id="one"> <div id="two"> <div id="three">AA</div> <a id="four" href="google.com"> BB </a> </div> </div>
1. Event
-
DOM Event는 구독방식으로 작동한다.
- 한 노드에 여러가지 이벤트를 등록 가능
- 같은 Event 타입으로 여러가지의 핸들러를 등록 가능
- 핸들러 작동 순서는 렉시컬 컨텍스트 순으로 작동된다.
-
이벤트 등록 방식은 on[eventTyp], addEventListener(eventType, callback)
-
on방식은 이벤트가 쉐도잉 처리 되기때문에, 마지막에 할당한 핸들러만 작동
- 쉐도잉은 on으로 등록된 이벤트만 처리되고, addEventListener는 정상 작동
-
addEventListener방식은 같은 이벤트에 여러 핸들러를 등록할 수 있다.
- 해당 이벤트가 dispatch 되면, 등록된 핸들러가 다 작동된다.
$four.addEventListener( 'click', (event) => { console.log('four addEventListener1') }, false ) $four.addEventListener( 'click', (event) => { console.log('four addEventListener2') }, false ) $four.onclick = (event) => { console.log('four onclick1') } $four.onclick = (event) => { event.preventDefault() console.log('four onclick2') } // four addEventListener1 // four addEventListener2 // four onclick2
-
-
모던 브라우저의 기본 이벤트 타입은 버블링이다
-
이벤트 리스너에서 처리하는게 버블링일뿐, 이벤트는
캡쳐링 → 버블링
-
addEventListner의 세번째 인자에 true로 바꾸면 캡쳐링
$one.addEventListener( 'click', (event) => { console.log('one') }, true ) $two.addEventListener( 'click', (event) => { console.log('two') }, false ) $three.addEventListener( 'click', (event) => { console.log('three') }, false ) // one // three // two
-
2. Event.preventDefault();
-
(
<a>
,<form>
) 태그의 기본 이벤트(브라우저에 정의된)를 막는다.<a id='four'>
기본 이벤트는 href에 등록된 주소로 페이지 이동preventDefault
때문에 기본 기능을 하지 못하고 콘솔이 찍힌다.
$four.addEventListener( 'click', (event) => { event.preventDefault() console.log('four') }, false ) // four (not move to google.com)
3. Event.stopPropagation()
-
브라우저의 이벤트 방식은
캡쳐링 → 버블링
으로 이벤트 전파된다-
document → body → target → body
document.addEventListener( 'click', (e) => { console.log('document') }, true ) document.addEventListener( 'click', (e) => { console.log('document') }, false ) document.body.addEventListener( 'click', (e) => { console.log('body') }, true ) document.body.addEventListener( 'click', (e) => { console.log('body') }, false ) $one.addEventListener( 'click', (event) => { console.log('one') }, true ) $one.addEventListener( 'click', (event) => { console.log('one') }, false ) // document -> body -> target -> body -> document
-
-
이러한 이벤트 전파 흐름을 막아준다
-
캡쳐링 / 버블링 관계없이 이벤트의 전파 흐름을 막는다.
document.addEventListener( 'click', (e) => { console.log('document') e.stopPropagation() }, true ) document.body.addEventListener( 'click', (e) => { console.log('body') }, false ) $one.addEventListener( 'click', (event) => { console.log('one') }, true ) $one.addEventListener( 'click', (event) => { console.log('one') }, false ) // document(더 이상 이벤트가 발생하지 않는다)
-
단, 해당 노드에 등록된 이벤트 핸들러들은 작동된다.
document.addEventListener( 'click', (e) => { console.log('document1') e.stopPropagation() }, true ) document.addEventListener( 'click', (e) => { console.log('document2') }, true ) document.body.addEventListener( 'click', (e) => { console.log('body') }, false ) $one.addEventListener( 'click', (event) => { console.log('one') }, true ) $one.addEventListener( 'click', (event) => { console.log('one') }, false ) // document1 // document2 (더 이상 이벤트가 발생하지 않는다)
-
4. Event.stopImmediatePropagation();
-
해당 요소에 동일한 이벤트타입으로 등록된 핸들러의 전파를 멈춘다
-
이벤트 핸들러는 등록 순서대로 작동된다(렉시컬 컨텍스트).
$three.addEventListener( 'click', (event) => { console.log('three1') }, false ) $three.addEventListener( 'click', (event) => { console.log('three2') }, false ) // three1 // three2
-
순서 document → target(handler1, handler2 ..) → document순
$three.addEventListener( 'click', (event) => { console.log('three1') }, false ) $three.addEventListener( 'click', (event) => { console.log('three2') event.stopImmediatePropagation() }, false ) $three.addEventListener( 'click', (event) => { console.log('three3') }, false ) // three1 // three2 $three.addEventListener( 'click', (event) => { console.log('three1') event.stopImmediatePropagation() }, false ) $three.addEventListener( 'click', (event) => { console.log('three2') }, false ) $three.addEventListener( 'click', (event) => { console.log('three3') }, false ) // three1
-
5. 특정 노드에 이벤트를 리셋시켜주고 싶을때는?
- 관련 API는 찾을 수 없었고, 새롭게 노드를 만들어주는 방법뿐이다.
elClone = $three.cloneNode(true) $three.parentNode.replaceChild(elClone, $three)