본문 바로가기
vue

[vue] vuex pathify를 사용한 dialog(모달창, 팝업창) 만들기

by devjh 2021. 11. 2.
반응형

이번게시글에서는 vuex-pathify를 사용하여 dialog 창 만드는 방법을 정리합니다.

 

소스코드는 https://github.com/jaeho310/vue-study (vuex-dialog 브랜치)에서 확인 가능합니다.

 

이전 게시글에서 내용이 추가된 예제입니다.

 

[vue] vuex-pathify를 사용한 메뉴바 구성하기(vuex-pathify 사용법)

vuex-pathify란 vue를 사용하다보면 컴포넌트간 데이터 교환을 해야하는 경우가 많습니다. 부모자식간의 통신의 경우 props emit을 활용하면 되지만 고조할아버지와 손자가 통신하는경우 props를 사용

frozenpond.tistory.com

 

결과화면

 

1. CustomDialog.vue 파일 생성

<template>
  <v-card>
    <v-card-title class="text-h5" v-if="question">
      confirm
    </v-card-title>
    <v-card-title class="text-h5" v-if="!question">
      alert
    </v-card-title>
    <v-card-text v-text="text"></v-card-text>
    <v-card-actions>
      <v-spacer></v-spacer>
      <v-btn
        v-if="!question"
        color="green darken-1"
        text
        @click="$emit('submit')"
      >
        ok
      </v-btn>
      <v-btn
        v-if="question"
        color="green darken-1"
        text
        @click="$emit('submit')"
      >
        yes
      </v-btn>
      <v-btn
        v-if="question"
        color="green darken-1"
        text
        @click="$emit('hide')"
      >
        no
      </v-btn>
    </v-card-actions>
  </v-card>
</template>

<script>
export default {
  name: 'CustomDialog',
  props: ["text", "question"],
}
</script>
<style>

</style>

 

입맛에 맞게 꾸며줍니다.
저는 yes or no, confirm으로 팝업창을 구성하였습니다.

 

2. utils/dialog.js 파일 생성

import store from '../store'

let __dialog = {
  dialogInfo: {
    text: "Dialog 메시지를 입력하세요",
    question: false,
    hideDialog: null,
    submitDialog: null,
  },
  showDialog: false,
  dialogCallback: function(){alert("dialog 콜백을 확인해주세요")},
  makeDialog: function(payload) {
    // alert창인지, yes or no question 인지
    if (payload.question != null) {
      this.dialogInfo.question = payload.question
    } else if (payload.question == null) {
      this.dialogInfo.question = false
    }

    // message 확인
    if (payload.text) {
      this.dialogInfo.text = payload.text
    } else {
      this.dialogInfo.text = "Dialog 메시지를 입력하세요"
    }

    // callback이 있는경우
    if (payload.callback != null) {
      this.dialogCallback = payload.callback
    } else {
      this.dialogCallback = null
    }

    // no를 누른경우
    this.dialogInfo.hideDialog = () => {
      this.showDialog = false
    }
    // yes를 누른경우 doalog창을 닫고 callback을 실행
    this.dialogInfo.submitDialog = () => {
      this.showDialog = false
      if (this.dialogCallback) {
        this.dialogCallback()
      }
    }

    if (payload.delay != null) {
      setTimeout(()=>{this.showDialog=true}, payload.delay)
    } else {
      this.showDialog = true
    }
    store.set('dialog/dialogManager', __dialog)
  }
}

export default __dialog

 

dialog를 위한 js 파일을 하나 만들어줍니다.
payload에는 text, question, callback, delay를 보낼 수 있게 해놨습니다.
해당 파일을 import를 한후 makeDialog메서드를 사용하게되면 vuex에 state인 showDialog가 ture로 변경하고

dialog창이 등장합니다.

 

3. store/modules/dialog.js 파일 생성

// Pathify
import { make } from 'vuex-pathify'

const state = {
  dialogManager: {
    dialogInfo: {
      text: "Dialog 메시지를 입력하세요",
      question: false,
      hideDialog: null,
      submitDialog: null,
    },
    showDialog: false,
    dialogCallback: ()=>{alert("dialog 콜백을 확인해주세요")}
  }
}

const mutations = make.mutations(state)

const actions = {}

const getters = {}

export default {
  namespaced: true,
  state,
  mutations,
  actions,
  getters,
}

mutation은 vuex-pathify의 make.mutations로 대체해버립니다.

 

4. store/modules/index.js 파일 생성

export { default as app } from './app'
export { default as dialog } from './dialog'

 

모듈별로 나눠 pathify를 연동하여 사용합니다.

 

5. layout/View.vue 파일 수정

<template>
  <v-main>
    <router-view />
    <v-dialog
      max-width="400"
      v-model="dialogManager.showDialog"
      >
        <CustomDialog
          :text="dialogManager.dialogInfo.text"
          :question="dialogManager.dialogInfo.question"
          @hide="dialogManager.dialogInfo.hideDialog"
          @submit="dialogManager.dialogInfo.submitDialog"
        />
    </v-dialog>
  </v-main>
</template>
<script>
import CustomDialog from '@/components/CustomDialog'
import { sync } from 'vuex-pathify'
export default {
  components: {
    CustomDialog
  },
  computed: {
      ...sync('dialog',[
        'dialogManager'
      ])
    },
}
</script>
<style>

</style>

 

dialog창을 사용하는곳마다 다 CustomDialog를 import 하고 props와 emit을 세팅할 수는 없습니다.
적당히 부모가 되는 컴포넌트에 CustomDialog를 넣어줍니다.
vuex와 pathify로 연결된 showDialog가 true가 되는순간 팝업창이 뜹니다.

 

이제 사용할 준비는 끝났습니다.

사용법입니다.

 

6. /views/Test.vue

<template>
    <v-card
      class="mx-auto mt-15"
      width="400"
    >
      <v-card-title>
        <span class="text-h5">메뉴 추가</span>
      </v-card-title>
      <v-card-text>
        <v-container>
          <v-row>
            <v-text-field
              v-model="inputValue"
              label="추가할 메뉴명을 입력해주세요"
            ></v-text-field>
          </v-row>
        </v-container>
      </v-card-text>

      <v-card-actions>
        <v-spacer></v-spacer>
        <v-btn
          color="blue darken-1"
          text
          @click="save"
        >
          저장
        </v-btn>
        <v-btn
          color="blue darken-1"
          text
          @click="toHome"
        >
          홈으로
        </v-btn>
      </v-card-actions>
    </v-card>
</template>

<script>
import dialog from '../utils/dialog.js'
import { sync } from 'vuex-pathify'
export default {
  name: "Test",
  data() {
    return {
      inputValue: '',
    }
  },
  methods: {
    save() {
      if (!this.inputValue) {
        dialog.makeDialog({text: "메뉴명을 입력해주세요"})
        return
      }
      this.items.push({
          title: this.inputValue,
          to : '/',
          icon: 'mdi-account'
      })
      dialog.makeDialog({text: "메뉴가 추가되었습니다."})
      this.inputValue = ''
    },
    toHome() {
      dialog.makeDialog({text: "홈으로 이동하시겠습니까?", question: true, callback: this.routerHome})
    },
    routerHome() {
      this.$router.push("/")
      dialog.makeDialog({text: "홈으로 이동되었습니다.", delay: 100})
    }
  },
  computed: {
    items: sync('app/items'),
  }
}
</script>

 

util에 만들어놨던 dialog.js를 import해서 사용합니다.

vuex를 사용하여  상위컴포넌트에서 dialog창을 띄워놨으므로
router.push를 사용하더라도 팝업창을 계속 사용 가능합니다.

반응형

댓글