2021_08_17

유지원·2021년 8월 17일
0

TIL - 이벤트 전파

DIV 영역, P 영역, SPAN 영역 각각에 클릭 이벤트를 걸었을 때 결과가 어떻게 나올까??

DIV 영역을 클릭했을 때는 DIV에 적용시킨 클릭 이벤트만 발생하지만 SPAN 영역을 클릭했을 때는 DIV, P, SPAN 영역에 적용시킨 클릭 이벤트가 모두 발생한다.
이는 이벤트 전파(전달)과 관련이 있다.

1. 이벤트 전파란??

이벤트 전파란 이벤트가 발생했을 때 브라우저가 이벤트 핸들러를 실행시킬 대상 요소를 결정하는 과정이다. 브라우저가 이벤트를 감지하는 방식은 2가지가 있다.

1-1 이벤트 버블링(bubbling)

이벤트가 발생한 element부터 상위 element에게 순차적으로 이벤트가 전파되는 방식이다.

<div className="Div1">
  <div className="Div2">
    <div className="Div3">
    </div>
  </div>
</div>
var divs = document.querySelectorAll('div');
divs.forEach((div) => {
  div.addEventListener('click', console.log(event.currentTarget.className))
}
//**출력결과**
// Div3
// Div2
// Div1

이벤트 버블링에 의해 Div3을 클릭했을 때 상위 element인 Div2, Div1도 출력이 된다.

1-2 이벤트 캡쳐링(capturing)

상위 element부터 이벤트가 발생한 element까지 순차적으로 이벤트가 전파되는 방식이다.

<div className="Div1">
  <div className="Div2">
    <div className="Div3">
    </div>
  </div>
</div>
var divs = document.querySelectorAll('div');
divs.forEach((div) => {
  div.addEventListener('click', console.log(event.currentTarget.className), {
    capture: true
  })
}
//**출력결과**
// Div1
// Div2
// Div3

이벤트 버블링과 달리 이벤트 캡쳐링 방식으로 수행하기 위해서는 이벤트 리스터의 세 번째 파라미터로 capture: true를 설정해 주어야 한다.
capture는 이벤트 리스너에 대한 특성을 지정하는 옵션 객체중 하나이다. default 값은 false로, true로 지정하면 이벤트 캡쳐링 방식으로 실행된다.

2. 이벤트 전파를 막기 위한 방법

이벤트 버블링, 캡쳐링을 원하는 만큼만 실행시키기 위해서는 이벤트 전파를 막는 메서드를 사용해야 한다. 이벤트 전파를 막기 위한 방법은 다음과 같다.

2-1. event.preventDefault()

현재 이벤트의 기본 동작을 차단하는 메서드이다.

<script>
  function handleClickLink(event) {
    event.preventDefault();
  }
</script>
<a href="https://www.naver.com/" onClick="handleClickLink(event)">네이버로 링크 이동</a>

a 태그는 기본적으로 클릭하면 href에 명시된 주소로 이동하는 이벤트 동작을 한다. 만약 a 태그의 기본 동작인 페이지 이동을 막기 위해서는 preventDefault 메소드를 이용할 수 있다.

2-2. event.stopPropagation()

// handleClickClose 함수에는 모달창을 닫는 코드가 작성되어있음
<div id="modal-background" onClick={() => handleClickClose()}> 
  <div id="modal-container">
    ~~~~~~
  </div>
</div>

물론 CSS가 필요하겠지만 위의 코드가 다음과 같은 모달을 출력한다고 가정해보자.

우리는 modal-background 영역을 클릭하면 모달창을 닫는 이벤트를 실행시키고 싶다. 그래서 해당 영역에 onClick 이벤트를 걸면 background 영역 뿐만 아니라 modal-container 영역에도 클릭 이벤트가 적용이 된다. 바로 이벤트 전파 때문이다.

우리는 이를 막기 위해 다음과 같이 코드를 수정해야 한다.

// handleClickClose 함수에는 모달창을 닫는 코드가 작성되어있음
<div id="modal-background" onClick={() => handleClickClose()}> 
  <div id="modal-container" onClick={(event) => event.stopPropagation()}>
    ~~~~~~
  </div>
</div>

이와 같이 작성하면 부모 element에는 onClick 이벤트가 적용되지만 stopPropagation 메서드로 인해 해당 영역에서는 클릭 이벤트가 적용되지 않는다.

2-3. event.stopImmediatePropagation()

같은 요소에 적용되는 다른 이벤트의 전파, 상위 요소로 가는 이벤트의 전파를 막는다.

window.addEventListener('click', () => console.log(1));
window.addEventListener('click', () => console.log(2));
window.addEventListener('click', () => console.log(3));
// 1 2 3

window 객체에 클릭 이벤트를 적용하면 콘솔에 출력되는 결과는 1 2 3이다.
만약 우리가 마지막 이벤트는 실행시키지 않고 싶다면 다음과 같이 하면 된다.

window.addEventListener('click', () => console.log(1));
window.addEventListener('click', (event) => {
  event.stopImmediatePropagation();
  console.log(2);
});
window.addEventListener('click', () => console.log(3));
// 1 2

stopImmediatePropagation 메서드를 이용하면 해당 이벤트까지 실행을 하고 다른 이벤트로의 전파를 막는다.

3. 이벤트 위임

'이벤트가 전파된다'는 특성을 이용해서 하위 요소에 각각 이벤트를 붙이지 않고 상위요소에서 하위 요소의 이벤트들을 제어하는 방식이다.

주로 태그마다 동일한 이벤트리스너를 반복적으로 붙이는 작업을 할 때 사용한다.
또한 동적으로 추가된 엘리먼트에 대해서도 기존의 엘리먼트들처럼 이벤트 발생에 따른 콜백을 실행해주고 싶을 때 사용해도 좋다.!

profile
안녕하세요 유지원입니다

0개의 댓글