본문으로 바로가기
728x90
반응형
728x170

얼마전 JS로 업무를 보던 중에 생겼던 일입니다. 그 문제들을 해결하기 위해 공부하며 알아왔던 것들을 공유하고자 올리게 되었습니다.

 

어떤 창 안에서 무언가를 삭제 하려 할 때 확인 팝업창이 뜨게 되는데 그 확인 창을 닫게 될 때 그 창도 같이 닫히게 되는 버블링 현상을 마주하였습니다.

 

좀 더 쉽게 설명하자면

예시로 다나와 견적함을 들자면 여기에서 SSD항목을 삭제하려 할 때 삭제하겠냐는 확인 창이 뜰 것이고, 확인, 취소를 누르면 견적함 창까지도 꺼졌던 것이지요.

 

이 문제를 해결하기 위해 이벤트 버블링에 대해 알아야했고, 그 전에 이벤트 등록에 대해 알고 있어야 했었습니다.

 

이벤트 등록이란 웹 애플리케이션에서 사용자의 입력을 받기 위해 필요한 기능입니다.

아래와 같은 코드를 말하는데

<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<button>print Event</button>
</body>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', printEvent);

function printEvent(event) {
	console.log(event);
}

</script>
</html>

print Event 버튼을 생성하였습니다. 이 버튼을 클릭 할 때 printEvent가 실행되게 되는데 그 때 event 인자가 넘어오게 되고,

받은 event를 콘솔에 찍어보면 event와 관련된 정보들을 확인 할 수 있습니다.

여기에서 addEventListener()가 화면에 동적인 기능을 추가하여 사용자의 입력에 따라 추가 동작을 구현 할 수 있는 위해 사용하는 기본적인 기능인데요.

 

여기서 브라우저가 어떻게 이벤트가 발생했다는 것을 감지하는 방식이 2가지가 있는데 이벤트 버블링(Event Bubbling) 이라는 방식과 이벤트 캡쳐(Event Capture) 방식이 있는데 지금은 이벤트 버블링만 다뤄보도록 하겠습니다.

 

이벤트 버블링(Event Bubbling)

이벤트 버블링은 특정 화면 요소에서 이벤트가 발생했을 때 해당 이벤트가 더 상위의 화면 요소들로 전달되어 가는 특성을 의미합니다.

그러니까 한 요소에 이벤트가 발생하면, 이 요소에 할당된 핸들러가 동작하고, 이어서 부모 요소의 핸들러가 동작합니다.

가장 최상단의 조상 요소를 만날 때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작하죠.

 

여기서 상위 화면 요소라는 것은 HTML 요소는 기본적으로 트리 구조를 갖는데 트리 구조상으로 한 단계 위에 있는 요소를 상위 요소라고 부릅니다.

 

이런 흐름을 '이벤트 버블링’이라고 부릅니다. 이벤트가 제일 깊은 곳에 있는 요소에서 시작해 부모 요소를 거슬러 올라가며 발생하는 모양이 마치 물속 거품(bubble)과 닮았기 때문입니다.'

 

위 그림을 코드로 표현하면 

<!doctype html>
<style>
  body * {
    margin: 10px;
    border: 1px solid blue;
  }
</style>

<body>
	<div class="one"> one
		<div class="two"> two
			<div class="three"> three
                <div class="four"> four
                </div>    
			</div>
		</div>
	</div>
</body>

<script>
    var divs = document.querySelectorAll('div');
    divs.forEach(function(div) {
        div.addEventListener('click', logEvent);
    });

    function logEvent(event) {
        console.log(event.currentTarget.className);
    }
</script>
</html>

이렇게 표현 할 수 있습니다. 

실행화면

위와 같은 화면을 볼 수 있는데요.

네 개의 div 태그에 모두 클릭 이벤트를 등록하고 클릭 했을 때 logEvent 함수를 실행시키는 코드입니다.

여기서 위 그림대로 최하위 div 태그 <div class="three"></div>를 클릭하면 아래와 같은 결과가 실행하게 되죠.

 

four div 태그 한 개만 클릭했을 뿐인데 왜 4개의 이벤트가 발생하게 됩니다. 그 이유는 브라우저가 이벤트를 감지하는 방식 때문인데요.

브라우저는 특정 화면 요소에서 이벤트가 발생했을 때 그 이벤트를 최상위에 있는 화면 요소까지 이벤트를 전파시킵니다. 

따라서, 클래스 명 four-> three -> two -> one 순서로 div 태그에 등록된 이벤트들이 실행됩니다.

마찬가지로 three 클래스를 갖는 두 번째 태그를 클릭했다면 three-> two -> one 순으로 클릭 이벤트가 동작하죠.

여기서 주의해야 할 점은 각 태그마다 이벤트가 등록되어 있기 때문에 상위 요소로 이벤트가 전달되는 것을 확인할 수 있습니다. 

만약 이벤트가 특정 div 태그에만 달려 있다면 위와 같은 동작 결과는 확인할 수 없습니다.

이와 같은 하위에서 상위 요소로의 이벤트 전파 방식을 이벤트 버블링(Event Bubbling)이라고 합니다.

 

해결 방법

그래서 이 버블링 현상을 해결하기 위해 사용했던 함수가 event.stopPropagation()입니다.

propagation의 사전적의미는 전파, 확산입니다. stopPropagation 은 부모태그로의 이벤트 전파를 stop 중지하라는 의미입니다.

 

<script>태그 안에 있는 코드를 아래와 같이 바꿔줍니다.

<script>
    var divs = document.querySelectorAll('div');
      divs.forEach(function(div) {
        div.addEventListener('click', logEvent);
    });

	function logEvent(event) {
        event.stopPropagation();
        console.log(event.currentTarget.className); // three
    }
</script>

 

그 후 실행시켜보면 이벤트 버블링 현상을 막아진 것을 확인 할 수 있습니다.

 

추가적으로 event.preventDefault()를 사용하시면 지정해둔 이벤트 외에 별도의 브라우저 행동을 막을 수 있어 더 안전하게 버블링을 막을 수 있습니다.

728x90
반응형
그리드형

댓글을 달아 주세요