이벤트 위임

Seung·2022년 2월 17일
0
  • Event Bubbling : 중첩된 요소에서 동일한 이벤트를 가지면 하위 요소에서 상위 요소로 이벤트를 전달하는 현상

  • Event Capturing : 중첩된 요소에서 동일한 이벤트를 가지면 상위 요소에서 하위 요소로 이벤트를 전달하는 현상

  • 기본적으로 브라우저는 capturing으로 시작해서 이벤트가 발생한 target까지 내려가면 다시 bubbling으로 올라간다

  • addEventListener의 3번째 인자에 true 지정시 capturing을 통해 이벤트 전파, false 지정시 bubbling으로만 이벤트 전파 (default : false)


😄 code. Bubbling, Capturing

/*HTML*/
<section class="container">
	<div class="outer">
    	<button class="middle">Click Me</button>
    </div>
</section>

/*JavaScript*/
const container = document.querySelector('.container');
const outer = document.querySelector('.outer');
const inner = document.querySelector('.inner');

container.addEventListener('click', (e) => {
	console.log(`container: ${e.currentTarget}, ${e.target}`);
});

outer.addEventListener('click', (e) => {
	console.log(`outer: ${e.currentTarget}, ${e.target}`);});

inner.addEventListener('click', (e) => {
	console.log(`inner: ${e.currentTarget}, ${e.target}`);});

첫번째 코드 결과값
container: [object HTMLElement], [object HTMLElement]

  • 제일 바깥에 있는 section에 click event가 발생했을 때 각각 e.currentTarget, e.target 값

e.currentTarget ?

  • 이벤트 리스너가 등록되어 있는 요소
  • 첫번째 코드에선 이벤트가 section에 등록되어 있기 때문에 HTMLElement를 반환

e.target ?

  • 이벤트가 발생한 대상 (최하위 요소)
  • 첫번째 코드에선 addEventListener의 3번째 인자값이 false(default)이기 때문에 이벤트가 Bubbling으로 전달되고 이벤트가 발생한 section이 최하위 요소이기 때문에 HTMLElement를 반환
    (이전 요소들만 반환하고 다음 요소들은 반환하지 않음)
    (section의 이전 요소로 body, html이 있지만 동일한 이벤트가 아니기 때문에 이벤트를 전달하지 않음)

두번째 코드 결과값
outer: [object HTMLDivElement], [object HTMLDivElement]

container: [object HTMLElement], [object HTMLDivElement]

  • 여기서 의문점이 생길 것이다. 첫번째 코드랑 두번째 코드 똑같이 요소 하나만 click을 해서 event가 발생했는데 첫번째 코드는 container 결과값만 나오고 두번째 코드는 container와 outer 두개의 결과값이 나왔다. Bubbling으로 인해 div의 이전 요소인 section 요소도 같이 반환된 것이다

e.currentTarget ?

  • .outer의 이벤트는 div에 등록되었기 때문에 HTMLDivElement 반환, .container의 이벤트는 section에 등록되었기 때문에 HTMLElement 반환

e.target ?

  • 이벤트 등록 여부, 전달과는 상관없이 이벤트 자체는 div 요소에서 발생했기 때문에 .outer와 .container 모두 HTMLDivElement 반환

세번째 코드 결과값
inner: [object HTMLButtonElement], [object HTMLButtonElement]

outer: [object HTMLDivElement], [object HTMLButtonElement]

container: [object HTMLElement], [object HTMLButtonElement]

  • 세번째 코드는 inner, outer, container 3개의 결과값이 나왔다

  • 이렇게 나온 이유 역시 Bubbling 떄문이다

Bubbling ?

  • 동일한 이벤트를 가질 때 해당 이벤트가 하위 요소에서 상위 요소로 전달 되는 것

  • 즉 위의 코드에서 HTML 구조는 session <- div <- button의 DOM Tree를 가진다

  • 쉽게 말해 위의 코드에서는 모두 click이라는 동일한 이벤트를 가지고있고 제일 하위요소인 button을 클릭했을 때 button에만 click 이벤트가 발생하는게 아닌 동일한 이벤트를 가진 상위요소인 div에도 동일한 이벤트가 발생하고 또 div와 동일한 이벤트를 가진 상위요소인 section에도 동일한 이벤트가 발생하는 현상을 Bubbling이라고 한다

  • 그래서 button을 클릭 했을 때 버블링에 의해 결과값이 3개가 나왔고 div를 클릭 했을 때는 동일한 이벤트를 가진 상위요소가 section밖에 없었기 때문에 결과값이 2개가 나온 것이다 (동일한 event를 가지고 있을 때만 발생)

😍 DOM Tree에 대한 자세한 설명은 제 벨로그에 있습니다 😍

Capturing

  • Bubbling 반대 개념으로 동일한 이벤트일 때 상위 요소에서 하위 요소로 이벤트가 전달 되는 현상

😄 이벤트 전파 중단

event.stopPropagation()

  • 현재 이벤트가 Capturing || Bubbling 단계에서 더 이상 다음 단계로 전파되지 않도록 중단 (이벤트 전달만 막고 다음 단계의 요소들이 개별적으로 가지고 있는 이벤트는 실행)

Event.stopImmediatePropagation()

  • 이벤트 전파도 막고 다음 단계의 요소들이 개별적으로 가지고 있는 어떠한 이벤트 핸들러의 실행도 막는다 (다른 요소들의 이벤트는 전부 취소하고 본인의 이벤트만 실행)

  • 위의 코드를 남용하는 사람들이 생각보다 많은데 정말 안좋은 습관이다

    • Why ? 사용자 입장에서 다음 단계에 더 의미 있는 이벤트가 있을수도 있는데 강제로 중단 시키는것은 좋지 않다 (버그 발생의 주 원인)

😍 코드 지적은 언제나 환영입니다. 읽어주셔서 감사합니다. 😍

profile
지적은 제 발전의 원동력입니다. 사소한 것이라도 지적해주세요 :)

0개의 댓글