Vue.js 모달(Modal) 컴포넌트 분리하기
Vue.js 모달(modal) 컴포넌트 구현하기
Vue.js 공식 문서를 참고해서 만들었습니다.[https://kr.vuejs.org/v2/examples/modal.html]
사용 언어
- vue-cli (class component 기반)
- typescript
모달창은 프로젝트 내에서 다양하게 쓰일 일이 많아서 따로 컴포넌트로 분리하여 구현하였습니다.
스타일은 각자의 상황에 따라 구현해주시면 좋을 것 같습니다
태그 부분
크게 header / body / footer로 나뉩니다.
- 각각의 레이아웃마다 확장성을 주기 위해 slot을 사용
header - 이미지 / 제목
-
현재 header에 이미지가 필요한 사항이라 추가적으로 이미지 태그를 사용했습니다.
-
태그는 퀘이사를 사용하였으므로 사용하시는 프레임워크의 태그로 대체 해주시면 됩니다. - 커스텀 이벤트 태그를 사용하였기 때문에 이미지를 사용하고 싶지 않은 경우 모달을 사용할 때 제외해주시면됩니다.
body - 바디
footer - 모달 종료 버튼
- 종료 버튼의 문구 유연성
스크립트
부모에게 전달하기 위한 prop
Modal.vue
<template>
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<q-img class="modal-img" :src="src"></q-img>
<slot name="header"></slot>
</div>
<div class="modal-body">
<slot name="body"> </slot>
</div>
<div class="modal-footer">
<slot name="footer"> </slot>
<div
@click="$emit('close')"
class="close-btn"
></div>
</div>
</div>
</div>
</div>
</transition>
</template>
<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
@Component({
components: {},
})
export default class GuideModal extends Vue {
@Prop() private src!: string;
@Prop() private close!: string;
}
</script>
<style scoped>
.modal-mask {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: table;
text-align: center;
transition: opacity 0.3s ease;
}
.close-btn{
color:#838282;
text-decoration: underline;
}
.close-btn:hover{
cursor: pointer;
}
.modal-img {
margin-top: 4%;
width: 55%;
}
.modal-wrapper {
display: table-cell;
vertical-align: middle;
}
.modal-container {
width: 40%;
height: 55%;
margin: 0px auto;
padding: 20px 30px;
background-color: #fff;
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
transition: all 0.3s ease;
font-family: Helvetica, Arial, sans-serif;
}
.modal-body {
margin: 20px 0;
}
.modal-default-button {
float: right;
}
/*
* The following styles are auto-applied to elements with
* transition="modal" when their visibility is toggled
* by Vue.js.
*
* You can easily play with the modal transition by editing
* these styles.
*/
.modal-enter {
opacity: 0;
}
.modal-leave-active {
opacity: 0;
}
.modal-enter .modal-container,
.modal-leave-active .modal-container {
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
</style>
modalTest.vue
<template v-if="modal">
<guide-modal @close="modal = false" :close="종료" src="이미지 경로">
<template v-slot:header >
<p class="header">헤더</p>
<p class="header-desc">헤더 디테일 </p>
</template>
<template v-slot:body >
/* 바디에 버튼을 사용해야해서 버튼을 추가
원하는 모든 태그 삽입가능
*/
<q-btn
class="modal-body-btn"
color="black"
text-color="white"
:label="버튼"
@click="movePage()"
/>
</template>
</guide-modal>
</template>
<script lang="ts">
import GuideModal from "layouts/guideModal.vue";
@Component({
components: {GuideModal}
})
export default class ModalTest extends Vue {
private modal: boolean = false;
movePage(){
window.location.href = 이동할 페이지 url
}
showModal(){
//모달을 보여주는 경우
this.modal=true;
//아닌경우
this.modal=false;
}
}
</script>
<style scoped>
.header{
color:#181818;
font-weight: bold;
font-size: 3rem;
}
.header-desc{
color: #181818;
font-size: 1rem;
}
.modal-body-btn{
margin-top: 20px;
border-radius: 40px;
padding: 0 20px 0 20px;
height: 60px;
font-size: 17px;
font-weight: bold;
}
</style>