minzzl

[Javascript] 이벤트 버블링과 캡처링 본문

프로젝트/자바스크립트

[Javascript] 이벤트 버블링과 캡처링

minzzl 2022. 10. 9. 20:38
728x90
반응형

웹 사이트에서 버튼을 클릭했다고 가정해봅시다.

만약 해당 버튼이 다음과 같다고 했을 때 이벤트의 시발점은 어디일까요?

<html>
	<body>
		<div>버튼</div>
	</body>
</html>

네 맞습니다.

div를 이벤트의 시발점이라고 하는데요, 즉 div를 눌렀을 때 클릭 이벤트가 있으면 실행이 됩니다. 

그런데, 우리는 div를 눌렀지만 div 하나 만을 눌렀다고 하기는 굉장히 애매합니다. 왜냐하면, div를 감싸는 body도 있고 그를 감싸는 html도 있기 때문입니다. 우리는 div를 클릭한것이라고 해야할까요? 아님 body를 클릭했다고 해야할까요?

 

그래서 브라우저는 우리가 div를 눌렀지만, div가 단독으로 있는 것이 아닌 여러개의 부모가 있다면, 만약 부모들에게도 click event가 있다면 다 같이 실행을 시켜버립니다. 도미노 처럼 말이죠. 즉 이벤트의 원인은 div이고 body와 html은 이벤트에 탑승하게됩니다. 

물론 body와 html에 click 이벤트가 없다면 아무 상관 없는 일입니다. 

 

이제 용어 정리를 해보겠습니다.

 

current target : 이벤트가 발생 할 때 이벤트의 진짜 주인

target : 그래서 이 이벤트가 누구 때문에 실행되었는가 하는 이벤트의 시발점

 

예시를 들어보겠습니다.

 

우리가 div를 클릭했을 때 div의 입장에서는 div에서 발생한 이벤트의 주인은 자기자신에 있는 이벤트일 것이기 때문에 Current target은 div입니다. 또한 그 이벤트가 일어난 원인도 자신이기때문에 target 또한 div 일 것입니다. 

 

 

그런데 body의 입장에서는 그 body안에 있는 event handler가 실행되었기 때문에 current target 은 자기자신일 것이지만, 그 이벤트가 일어난 원인은 div이므로 target은 div가 됩니다.

 

이와 같이 우리는 current target과 target을 분리해서 생각해야합니다.

또한 이 처럼 하나의 div를 클릭을 통해 실행 시킨다고 했을 때 관련된 관련자들을 모두 실행시키다보니, 순차적으로 실행을 시켜야하는 문제가 발생합니다. 달리 말하면 div, body, html 을 실행 시켜야하는데 누구 먼저 실행을 시켜야하는가에 대한 문제가 발생합니다. 그래서 event는 event flow를 가집니다.

 

근데 그 flow는 딱 정해져있습니다.

 

1. 가장 상위 요소인 html 부터 시작이되며 이를 capture phase 라고 합니다. (propagate up)

2. event가 시작된 당사자 event가 실행되며 이를 target phase 라고 합니다.

3. 다시 그 다음 부모로 내려가는 것을 bubble phase 라고 합니다. (propagate down)

 

다음과 같은 순서를 통해 실행이 된다면

1. html

2. body

3. div

4. body

5. html

 

쓸데없이 중복으로 처리되는 부분들이 생기는 것 같습니다.

 

그래서 브라우저는 제약을 둡니다.

currentTaget과 target이 일치하지 않는 경우, capture 단계에서 실행이 될지 bubble 단계에서 실행이 될지 선택할 수 있도록 해줍니다.

참고로 default 값은 bubble 입니다.

위 그림의 실행 순서는 다음과 같습니다

1. html

2. div

3. body

 

이벤트 버블링

 

이벤트 버블링이란 한 요소에 이벤트가 발생하면 이 요소에 할당된 핸들러가 동작하고, 이어서 부모 요소의 핸들러, 최상단의 부모 요소를 만날 때까지 반복되면서 핸들러가 동작하는 현상을 말한다.

예제 코드

 <body>
    <div class="DIV1">
      DIV1
      <div class="DIV2">
        DIV2
        <div class="DIV3">DIV3</div>
      </div>
    </div>
  </body>
const divs = document.querySelectorAll("div");

const clickEvent = (e) => {
  console.log(e.currentTarget.className);
};

divs.forEach((div) => {
  div.addEventListener("click", clickEvent);
});

div를 클릭하면 해당하는 클래스의 이름이 콘솔로 출력되는 코드이다. 자바스크립트는 기본적으로 버블링이 발생하기 때문에 <div class="DIV3">DIV3</div>를 클릭한다면 콘솔에는 DIV3, DIV2, DIV1이 순서대로 출력이 될 것입니다.

 

 

이벤트 캡처링

 

이벤트 캡처링은 버블링과는 반대로 최상단에서 해당 태그를 찾아 내려간다.
addEventListener의 옵션 객체에 { capture: true }또는 true를 설정해주면 캡처링을 구현할 수 있다.

예제 코드

const divs = document.querySelectorAll("div");

const clickEvent = (e) => {
  console.log(e.currentTarget.className);
};

divs.forEach((div) => {
  div.addEventListener("click", clickEvent, { capture: true });
});

 

이벤트 전파막기

 

버블링은 해당 타깃에서 document 객체를 만날 때까지 핸들러가 모두 호출되는데 코드를 작성하다보면 원하는 타깃에서만 이벤트를 발생하게 하고 싶을때가 있습니다.

그럴 때에는 event.stopPropagation() 을 사용하면 되는데 버블링의 경우에는 클릭한 타깃의 이벤트만 발생하고 상위 요소로 이벤트가 전파되는 것을 막을 수 있습니다. 다음과 같이 코드를 작성한다면 클릭한 타켓에서만 이벤트가 발생합니다.

const clickEvent = (e) => {
  e.stopPropagation();
  console.log(e.currentTarget.className);
};

 

 

*아래의 글을 참고하여 작성하였습니다.

https://velog.io/@tlatjdgh3778/%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%B2%84%EB%B8%94%EB%A7%81%EA%B3%BC-%EC%BA%A1%EC%B2%98%EB%A7%81%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A0%95%EB%A6%AC

https://www.youtube.com/watch?v=7gKtNC3b_S8

728x90
반응형

'프로젝트 > 자바스크립트' 카테고리의 다른 글

[Javascript] Scope 와 Closure  (0) 2022.10.09
[Javascript] this  (0) 2022.10.09
[Javascript] 비동기처리 callback, promise, aync/await  (0) 2022.10.09
[Javascript] JSON  (0) 2022.10.09