티스토리 뷰
모바일 환경에서 모달창이 떠 있는 상태에서 모달을 닫는 방법은 여러가지가 있을 수 있는데, 그 중 첫 번째 방법은 모달 창 내부에 별도의 'X'버튼을 표시해서 이 영역을 터치하면 닫히게 하는 방법이 있다. 가장 직관적인 방법이지만 버튼을 위한 별도의 공간을 확보해야 하기 때문에 디자인상 의도치 않은 공간을 차지한다는 단점이 있다. 이런 단점을 해결하기 위한 두 번째 방법은 모달 바깥의 영역을 터치를 감지했을 때 모달을 닫는 방법이 있다. 다만 이 방법 역시 명시적인 '닫기'버튼이 보이지 않기 때문에 이러한 UI/UX가 낯선 사용자에게는 모달을 어떻게 닫아야 하는지 헤맬 수도 있다는 단점이 있다. 세 번째 방법은 (안드로이드 환경에서) 뒤로가기 버튼을 눌렀을 때 모달이 닫히게 하는 방법이다. 이 방법의 경우, 모달창과 직접적인 상호작용이 일어나지 않으므로 개발자 입장에서는 뒤로가기 이벤트를 감지해야 하는 등 꽤나 까다로운 작업이다. 이번 글에서는 그 방법에 대해서 설명하겠다.
지난 글에서 작성했던 TeleportModal.vue
를 재사용 한다.
뒤로가기를 눌렀을 때 모달창이 닫히게 만들기 위해서는, 모달창이 열려있는 상태를 window 전역객체의 history에 저장(push)해야 한다. 이때 사용하는 함수가 window.history.pushState()
함수이다. 이 함수에 대한 자세한 설명은 MDN을 참고하기 바란다.pushState()
함수의 첫 번째 인자로는 state
를 전달해야 하는데, 정해진 양식이 있는 것이 아니라 개발자가 식별할 수 있는 정보를 담아서 객체 형태로 넘기기만 하면 된다. 나는 {page : 'modal'}
객체를 넣었다.
// TeleportModal.vue
// template
<teleport to="#desktop-modal">
<div class="modal">
<transition name="slide-up" appear>
<div class="modal-content" >
<h1>This is Modal</h1>
</div>
</transition>
</div>
</teleport>
// script
export default{
setup(){
onMounted(() => {
history.pushState({ page: 'modal' }, document.title);
});
}
}
그리고 모달창 버튼은 임시로 TopMenuBar.vue
에다가 위치시키고, v-if
를 통해 modalStore
의 modal
값에 따라서 표출여부를 결정하였다.
// TopMenuBar.vue
<template>
<nav>
...
<router-link to="" @click="modalStore.openModal()">Modal</router-link>
<TeleportModal v-if="modalStore.modal" />
</nav>
</template>
모달창이 열리고, 닫히는 상태는 vue의 전역상태관리 라이브러리 pinia를 통해서 관리한다. 모달창을 열기 위해서는 modalStore.openModal()
함수를 호출하면 된다. 이 함수가 호출되면 state.modal
의 값이 true
가 되면서 v-if
로 걸려있었던 <TeleportModal>
이 렌더링된다.
// stores/modal.js
import { defineStore } from "pinia";
export const useModalStore = defineStore("modal", {
state: () => {
return {
modal: false
};
},
actions: {
openModal() {
this.modal = true;
},
closeModal() {
this.modal = false;
}
});
이제 버튼을 누르면 모달창이 켜지면서 동시에 history에도 모달이 켜져 있는 상태가 추가될 것이다. 이 상태에서 '뒤로가기' 버튼을 누르면 모달창이 꺼짐을 확인해볼 수 있다.
여기까지가 위에서 설명했던 모달창은 닫는 3가지 방법 중에서 세 번째 방법이고 첫 번째 방법과 두 번째 방법도 설명하겠다.
우선 '닫기'버튼을 눌러서 모달창을 닫기 위해서는 modalStore.closeModal()
함수를 호출하면 된다. 모달 바깥의 영역을 터치했을 때 닫히게 하려면 @vueuse/core 가 제공하는 onClickOutside
함수를 이용하면 된다. vue의 template ref
로 모달 영역을 잡아준 다음에 onClickOutside
함수의 인자로 넣고, 콜백으로 modalStore.closeModal()
해주면 된다.
다만 이렇게 했을 경우 문제가 하나 생긴다.
모달이 열릴 때(onMounted
할 때) history.pushState()
를 해주었기 때문에 또 다른 페이지가 이미 열려있는 상태이다. 여기서 뒤로가기를 누르면 이 상태가 닫히므로 아무 문제가 없지만, 뒤로가기를 누르지 않고 첫 번째, 두 번째 방법으로 모달을 닫을 경우에는 closeModal
함수 호출과 함께 반드시 현재 페이지를 스스로 pop 해주어야 한다. 즉 history.back()
을 호출해주어야 한다.
'Dev' 카테고리의 다른 글
vue에서 input을 커스텀 컴포넌트화 시키기 (0) | 2023.04.04 |
---|---|
vue에서 router내 DOM을 querySelector로 찾지 못하는 문제 (0) | 2023.04.04 |
vue3 modal transition(모달 트랜지션) (0) | 2023.03.09 |
vue3 route transition(라우트 트랜지션) (0) | 2023.03.09 |
vue-chart-3에서 비동기 통신 이후 데이터 그리기 (0) | 2023.03.09 |