[to-do-app] Vue 모달 컴포넌트
🧶 𝗪𝗲𝗯/Vue

[to-do-app] Vue 모달 컴포넌트

웹에서 자주 쓰는 모달 컴포넌트에 대해서 포스팅을 해보고자 합니다.

강의를 들으면서 모달을 띄우는 것에 오류가 있었는데 해결을 해서 기쁘네요. 그럼 글 시작하겠습니다.


 

 모달 컴포넌트 붙여넣기 

Document

https://kr.vuejs.org/v2/examples/modal.html

 

모달 컴포넌트 — Vue.js

Vue.js - 프로그레시브 자바스크립트 프레임워크

kr.vuejs.org

도큐먼트는 다음 주소창으로 이동하면 나옵니다. 해당 도큐먼트에서 다음 코드들을 가져옵니다.

 

 

Modal Html 코드

<Transition name="modal">
    <div class="modal-mask" v-if="showModal">
        <div class="modal-wrapper">
            <div class="modal-container">
                <!-- modal header -->
                <div class="modal-header">
                    <slot name="header"> default header </slot>
                </div>

                <!-- modal body -->
                <div class="modal-body">
                    <slot name="body"> default body </slot>
                </div>

                <!-- modal footer-->
                <div class="modal-footer">
                    <slot name="footer"> default footer </slot>
                </div>
            </div>
        </div>
    </div>
</Transition>

 

 

Modal CSS 코드

.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;
	transition: opacity 0.3s ease;
}

.modal-wrapper {
	display: table-cell;
	vertical-align: middle;
}

.modal-container {
	width: 300px;
	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-header h3 {
	margin-top: 0;
	color: #42b983;
}

.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-from {
	opacity: 0;
}
.modal-leave-active {
	opacity: 0;
}
.modal-enter-from .modal-container,
.modal-leave-active .modal-container {
	-webkit-transform: scale(1.1);
	transform: scale(1.1);
}

해당 코드들을 components 폴더 밑에 common 폴더를 만들어서 Modal.vue 파일에 복사 붙여넣기 합니다.

재사용성을 위하여 따로 common 폴더에 빼놓습니다.

 

 

components/common/Modal.vue

더보기
<template>
	<Transition name="modal">
		<div class="modal-mask" v-if="showModal">
			<div class="modal-wrapper">
				<div class="modal-container">
					<!-- modal header -->
					<div class="modal-header">
						<slot name="header"> default header </slot>
					</div>

					<!-- modal body -->
					<div class="modal-body">
						<slot name="body"> default body </slot>
					</div>

					<!-- modal footer-->
					<div class="modal-footer">
						<slot name="footer"> default footer </slot>
					</div>
				</div>
			</div>
		</div>
	</Transition>
</template>

<script>
export default {
	props: ["showModal"],
};
</script>

<style>
.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;
	transition: opacity 0.3s ease;
}

.modal-wrapper {
	display: table-cell;
	vertical-align: middle;
}

.modal-container {
	width: 300px;
	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-header h3 {
	margin-top: 0;
	color: #42b983;
}

.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-from {
	opacity: 0;
}
.modal-leave-active {
	opacity: 0;
}
.modal-enter-from .modal-container,
.modal-leave-active .modal-container {
	-webkit-transform: scale(1.1);
	transform: scale(1.1);
}
</style>

그러면 다음과 같습니다. 일단 Modal 컴포넌트를 만들었습니다.

 

 

 

 모달 컴포넌트를 사용할 상위 컴포넌트 TodoInput 

모달 컴포넌트 사용 - html

<!-- showModal 이 true 면 모달이 보인다-->
<!--close 이벤트가 되면 showModal이 false가 된다.-->
<Modal v-bind:showModal="showModal">
    <template v-slot:header>
        <h3>
            경고!
            <i class="fa-solid fa-xmark closeModalBtn" @click="showModal = false"></i>
        </h3>
    </template>
    <template #body>할 일을 입력해주세요.</template>
    <template #footer>copy right</template>
</Modal>

showModal 데이터true 가 되면 Modal 컴포넌트가 보이게 됩니다.

 

 

모달 컴포넌트 사용 - js

data() {
    return {
        newTodoItem: "",
        showModal: false,
    };
},

showModal 데이터를 선언해야 이를 사용할 수 있습니다.

addTodo() {
    // 값이 있을때만 실행
    if (this.newTodoItem !== "") {
        this.$emit("addTodoItem", this.newTodoItem);
        this.clearInput();
    } else {
        this.showModal = true;
    }
},

addTodo() 함수를 수정합니다.

else 구문을 붙여 만약 빈 칸을 입력하면 showModal 변수가 true 가 되도록 설정합니다.

 

 

slot

https://kr.vuejs.org/v2/guide/components-slots.html

 

슬롯(Slots) — Vue.js

Vue.js - 프로그레시브 자바스크립트 프레임워크

kr.vuejs.org

slot 을 사용하면 재사용성이 좋아집니다.

 

<div class="modal-header">
    <slot name="header"> default header </slot>
</div>

모달 컴포넌트에서 <slot></slot> 태그를 이용하여 선언된 곳의 내용을 사용자 나름대로 커스텀할 수 있습니다.

<template v-slot:header>
    <h3>
        경고!
        <i class="fa-solid fa-xmark closeModalBtn" @click="showModal = false"></i>
    </h3>
</template>
<template #body>할 일을 입력해주세요.</template>
<template #footer>copy right</template>

이는 상위 컴포넌트인 TodoInput 에서 변경이 가능합니다.

1. v-slot:"name"
<template v-slot:name> 커스텀 내용 </template>

2. #name
<template #name ></template>

이렇게 slot 을 사용할 때는 두 가지의 문법을 지켜야 합니다. 유의하시길 바랍니다.

 

 

components/TodoInput.vue

더보기
<template>
	<div class="inputBox shadow">
		<input type="text" v-model="newTodoItem" v-on:keyup.enter="addTodo" />
		<span class="addContainer">
			<i class="fa-solid fa-plus addBtn" v-on:click="addTodo"> </i>
		</span>

		<!-- showModal 이 true 면 모달이 보인다-->
		<!--close 이벤트가 되면 showModal이 false가 된다.-->
		<Modal v-bind:showModal="showModal">
			<template v-slot:header>
				<h3>
					경고!
					<i class="fa-solid fa-xmark closeModalBtn" @click="showModal = false"></i>
				</h3>
			</template>
			<template #body>할 일을 입력해주세요.</template>
			<template #footer>copy right</template>
		</Modal>
	</div>
</template>

<script>
import Modal from "./common/Modal.vue";

export default {
	// data(): function() {}
	data() {
		return {
			newTodoItem: "",
			showModal: false,
		};
	},

	components: {
		Modal,
	},

	methods: {
		// addTodo: function() {}
		addTodo() {
			// 값이 있을때만 실행
			if (this.newTodoItem !== "") {
				this.$emit("addTodoItem", this.newTodoItem);
				this.clearInput();
			} else {
				this.showModal = true;
				console.log(this.showModal);
			}
		},

		clearInput() {
			this.newTodoItem = "";
		},
	},
};
</script>

<style soped>
.hi {
	background-color: #42b983;
}
input:focus {
	outline: none;
}
.inputBox {
	background: white;
	height: 50px;
	line-height: 50px;
	border-radius: 5px;
}
.inputBox input {
	border-style: none;
	font-size: 0.9rem;
}
.addContainer {
	float: right;
	background: linear-gradient(to right, #6478fb, #8763fb);
	display: block;
	width: 3rem;
	border-radius: 0 5px 5px 0;
}
.addBtn {
	color: white;
	vertical-align: middle;
}
.closeModalBtn {
	color: #42b983;
}
</style>

또한 Modal 컴포넌트로 showModal 데이터를 전달해야지 모달 transition 을 사용할 수 있습니다.

그렇지 않으면 transition 이 제대로 동작하지 않습니다.

v-bind 를 통해 showModal 을 내려줍시다.

 

 

 

 결과 화면 

트랜지션과 모달이 제대로 동작하는 것을 확인할 수 있습니다. ✨

 

 

 

 

vue transition 오류

vue modal transition

vue modal

vue 모달

vue 모달 트랜지션


 

728x90