[vue] 모달 공용컴포넌트로 만들어 띄우기

Yeong·2024년 7월 16일
0

새로 프로젝트를 진행하던 중 모달은 사용하는 경우가 많으니 공용컴포넌트로 만들어서 관리하는 것이 좋다고 생각하여 만드는 과정을 한번 정리하면 좋을 것 같아서 정리 시작!

1. TheModal.vue 공용컴포넌트 만들기

<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을 이용해서 타이틀, 내용, 버튼을 공용으로 사용할 수 있도록 하였다.

2. TheModal을 이용하여 모달컴포넌트 생성(mapModal.vue)

<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 이렇게 사용하였고, 내가 넣으려는 문장이나 구조를 넣으면 된다.

3. 상태관리는 Store 에서 !

//store.js

state: {
	modal: {
 		mapModal: false;
 	}
},
mutations: {
        SET_MODAL(state, modalName) {
          state.modal[modalName] = !state.modal[modalName];
        },
}        

모달의 종류가 많을 것을 예상해 객체형태로 담았으며, 상태관리를 해주어야하니 mutation으로 동작하도록 했다.

4. 이제 mapModal을 가져와서 사용하자

<MapSaveModal v-if="modal.favoriteModal" />

나는 모달이 필요한 페이지 내에 import 해주었으며 v-if 를 통해 연결해주었다.

0개의 댓글

관련 채용 정보