새로 프로젝트를 진행하던 중 모달은 사용하는 경우가 많으니 공용컴포넌트로 만들어서 관리하는 것이 좋다고 생각하여 만드는 과정을 한번 정리하면 좋을 것 같아서 정리 시작!
<template>
<div :class="$style.modalWrap">
<div :class="$style.container">
<form
:class="$style.content"
:style="{ width: width }"
@submit.prevent="$emit('onSubmit')"
>
<h3 :class="$style.modalTitle">
<slot name="title"></slot>
</h3>
<div :class="$style.desc">
<slot name="desc"></slot>
</div>
<div :class="$style.btnWrap">
<slot name="btnWrap"></slot>
</div>
</form>
</div>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
export default {
props: {
width: {
type: String,
default: '450px',
},
},
computed: {
...mapState('auth', ['modal']),
},
methods: {
...mapMutations('auth', ['SET_MODAL']),
toggleModal() {
this.SET_MODAL('favoriteModal');
}
}
}
</script>
<style module>
.modalWrap {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.4);
display: flex;
justify-content: center;
align-items: center;
z-index: 999;
}
.container {
background: #fff;
border-radius: 10px;
padding: 20px;
box-sizing: border-box;
}
.content {
width: 100%;
max-width: 550px;
background-color: #fff;
box-shadow: 0 2px 7px rgba(0, 0, 0, 0.3);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border-radius: 8px;
padding: 1rem 1.5rem;
animation: scaleUp 0.3s;
}
.modalTitle {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 5px;
width: 100%;
font-size: 1.5rem;
font-weight: 600;
margin: 2rem 0;
}
.modalTitle span {
color: #2c9dec;
font-size: 1.2rem;
}
.btnWrap {
display: flex;
justify-content: center;
gap: 0.6rem;
width: 100%;
margin-top: 2rem;
}
</style>
먼저 slot을 이용해서 타이틀, 내용, 버튼을 공용으로 사용할 수 있도록 하였다.
<template>
<TheModal width="500px" @onSubmit="savePlace">
<template #title>
장소 저장하기
</template>
<template #desc>
해당 장소를 저장해볼게요?
</template>
<template #btnWrap>
<button @click="closeModal">닫기</button>
</template>
</TheModal>
</template>
<script>
import {mapMutations, mapState} from "vuex";
export default {
computed:{
...mapState('auth', ['modal'])
},
methods: {
...mapMutations('auth', ['SET_MODAL']),
closeModal() {
this.SET_MODAL('favoriteModal');
},
savePlace() {
console.log('장소 저장하기')
}
},
}
</script>
<template v-slot>
대신 #title
이렇게 사용하였고, 내가 넣으려는 문장이나 구조를 넣으면 된다.
//store.js
state: {
modal: {
mapModal: false;
}
},
mutations: {
SET_MODAL(state, modalName) {
state.modal[modalName] = !state.modal[modalName];
},
}
모달의 종류가 많을 것을 예상해 객체형태로 담았으며, 상태관리를 해주어야하니 mutation으로 동작하도록 했다.
<MapSaveModal v-if="modal.favoriteModal" />
나는 모달이 필요한 페이지 내에 import 해주었으며 v-if 를 통해 연결해주었다.