티스토리 뷰
이벤트 객체의 메서드인 Event.stopPropagation() 를 이해하기 위해 일단 이벤트 버블링에 대해 알아보자.
버블링이란?
버블링이란 한 요소에 이벤트가 발생하면, 이 요소에 할당된 핸들러가 동작하고, 이어서 부모 요소의 핸들러가 동작하는 것을 말하며, 가장 최상단의 조상 요소를 만날 때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작한다.
간단한 예시를 통해 버블링이 어떻게 발생하는지 알아보자.
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>
가장 안쪽의 <p> 요소를 클릭하면 다음과 같은 순서로 동작이 나타난다.
- <p> 에 할당된 onclick 핸들러가 동작함.
- <div> 에 할당된 onclick 핸들러가 동작함.
- <form> 에 할당된 onclick 핸들러가 동작함.
- document 객체를 만날 때까지, 각 요소에 할당된 onclick 핸들러가 동작함
위의 동작 방식에 의해 <p> 요소를 클릭하면 p -> div -> form 순서로 3개의 얼럿 창이 뜨며, 이런 흐름을 '이벤트 버블링'이라 한다.
그렇다면 <p> 요소를 클릭 시에, 이벤트 버블링으로 인해 div와 form 에 적용된 이벤트가 발생하지 않도록 하려면 어떻게 해야 할까? 이때 사용되는 이벤트 객체의 메서드가 event.stopPropagation() 이다. event.stopPropagation() 은 현재 이벤트 이후의 전파를 막아 위쪽으로 일어나는 이벤트 버블링을 막아 준다.
event.stopPropagation()을 활용한 모달
event.stopPropagation() 를 활용하여 다음과 같이 동작하는 모달(Modal)을 만들어 보려고 한다.
- 모달 바깥 영역에 onclick 이벤트 시에 closeModal() 함수를 통해 모달 닫기
- 모달 영역 내의 모달 닫기 버튼이 onclick 이벤트 시에 closeModal() 함수를 통해 모달 닫기
이때, [모달] 영역 내의 [모달 닫기 버튼]을 클릭 시에, 정상적으로 모달이 닫히기는 하지만, 이벤트 버블링 때문에 콘솔을 통해 에러가 발생하는 것을 알 수 있다. [모달 닫기 버튼]을 클릭 시, closeModal() 함수를 통해 모달에 대한 요소를 삭제하는데, 버블링을 통해 모달 바깥 영역에 적용된 closeModal() 함수가 다시 호출되면서, 이미 삭제한 모달요소를 다시 삭제하려니 에러가 발생하는 것이다.
또한 모달 영역에서 [모달 닫기 버튼] 영역을 제외한 부분을 클릭하면, 버블링 때문에 모달 바깥 영역의 클릭 이벤트가 발생하여 모달이 닫히는 문제가 발생한다.
따라서 이러한 에러를 막기 위해, [모달] 영역에 click 이벤트 시에 event.stopPropagation() 을 적용하자. 그려면, [모달] 영역 밖에서 발생하는 이벤트 버블링을 막아주는 동시에 [모달] 내부에서 [모달 닫기 버튼] 영역을 제외한 부분을 클릭하면 모달이 닫히는 문제를 해결할 수 있다.
[ 전체 코드 ]
style.css
body{
position:relative;
}
.open-modal-btn {
width: 120px;
height: 40px;
background-color: aquamarine;
cursor: pointer;
border-radius: 20px;
display: flex;
justify-content: center;
align-items: center;
}
.open-modal-btn:hover {
background-color: aqua;
}
.modal-wrapper {
position: fixed;
left: 0;
bottom: 0;
top: 0;
right: 0;
z-index: 999;
background-color: rgba(0,0,0,.1);
display: flex;
justify-content: center;
align-items: center;
}
.modal {
width: 200px;
background-color: white;
border: 1px solid gray;
border-radius: 20px;
}
.modal-content {
padding: 10px;
display: flex;
justify-content: center;
align-items: center;
}
.modal-content span {
text-align: center;
}
.close-modal-btn {
background: transparent;
cursor: pointer;
border-top-style: solid;
border-top-color: gray;
border-top-width: 1px;
text-align: center;
padding: 10px;
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Event Propagation</title>
<link rel="stylesheet" href="style.css">
</head>
<body class="container" >
<div class="open-modal-btn" onclick="openModal();">Open Modal</div>
<script>
const bodyElem = document.querySelector('.container');
const closeModal = (event) => {
const modalWrapperElem = document.querySelector('.modal-wrapper');
bodyElem.removeChild(modalWrapperElem)
}
const stopPropagation = (e) => {
e.stopPropagation();
}
const openModal = () => {
const modalWrapperElem = document.createElement('div');
modalWrapperElem.addEventListener("click", closeModal);
modalWrapperElem.classList.add('modal-wrapper');
const modalElem = document.createElement('div');
modalElem.classList.add('modal');
modalElem.addEventListener('click', stopPropagation);
const modalContentElem = document.createElement('div');
modalContentElem.classList.add('modal-content');
modalContentElem.innerHTML = `
<span>This is Modal</span>
`
const closeBtn = document.createElement('div')
closeBtn.classList.add('close-modal-btn')
closeBtn.innerHTML = "닫기";
closeBtn.addEventListener("click", closeModal);
modalElem.appendChild(modalContentElem)
modalElem.appendChild(closeBtn)
modalWrapperElem.appendChild(modalElem)
bodyElem.appendChild(modalWrapperElem)
}
const init = () => {
const openModalBtnElem = document.querySelector('.open-modal-btn');
openModalBtnElem.addEventListener('click', openModal);
}
document.addEventListener('road', () => {
init();
})
</script>
</body>
</html>
[ 참고 자료 ]
'개발' 카테고리의 다른 글
[JS] Intersection Observer API 사용법과 활용 (0) | 2021.10.30 |
---|---|
[JS] 비밀번호 유효성 검사 (0) | 2021.10.29 |
[CSS][JS] 간단한 Progress Bar 만들기 (0) | 2021.10.24 |
[JAVA] JSP 기본문법 - 주석/선언/표현식/스크립트릿 (0) | 2019.05.22 |
[JAVA] JSP 내장객체 - out (0) | 2019.05.22 |
- Total
- Today
- Yesterday
- C++ string
- react-native-swipe-list-view
- Java
- C++
- TODOLIST
- servlet 생명주기
- sevlet
- HTML
- loading bar
- 바닐라자바스크립트
- 자바스크립트
- 개발
- CSS
- string
- JSP
- 리액트 네이티브
- 비밀번호 유효성 검사
- rn
- VanilaJS
- ReactNative
- 리액트 네이티브 모듈
- Android
- Servlet
- 바닐라 자바스크립트
- ReacNative
- JSP 내장객체
- 투두리스트
- string 생성
- web
- JavaScript
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |