Web Development

Vue3로 팝업창 만들기

2023. 01. 13. by 박하람

Vue3 버전으로 웹 서비스를 베타로 운영하고 있다. 사용자가 홈페이지에 처음 들어올 때, 베타 버전이라고 안내하고 싶어서 팝업창을 하나 만들었다. 바닐라 JS로 모달창을 만드려면 꽤나 코드량이 많았을 것 같은데, vue로 만드니 훨씬 간단하다!

단계별 방법

단계별 방법은 간단하다. 기본적으로 팝업창은 이미 만들어졌다고 가정한다.

  • 1단계: 컴포넌트로 미리 팝업창과 관련된 html, css 구조 짜놓기
  • 2단계: 팝업창이 뜰 페이지에 컴포넌트를 집어넣기
  • 3단계: 팝업창이 없어지는 이벤트 구현하기

1단계: 팝업창 컴포넌트 만들기

팝업창은 tailwind css를 사용하여 만들었다. 닫기(X)의 디자인과 호버 효과는 Flowbite의 일부를 가져왔다. 본인이 원하는 디자인으로 팝업창을 만들면 된다.

modal design

2단계: 팝업창이 뜰 페이지에 컴포넌트 추가하기

이 팝업창은 처음 웹 서비스에 접속하는 홈페이지에 띄울 것이다. views 폴더 내부에 있는 index.vue에 컴포넌트를 등록한 후, 인덱스 페이지의 가장 상단에 해당 컴포넌트를 추가한다. 완성된 팝업창은 다음 그림과 같다.

<template>
  <div class="w-full bg-white">
    <!-- popup window -->
    <PopUpView v-if="this.openModal == true" />
    ...
  </div>
</template>

<script>
import PopUpView from '@/components/PopUpView.vue' // 컴포넌트 불러오기
export default {
  name: 'IndexView',
  components: {
    PopUpView, // 여기에 추가해주기
  },
  ...
}
</script>

3단계: 이벤트 구현하기

사용자가 팝업창의 닫기(X)를 클릭하면, 팝업창이 닫히는 것을 구현해보자. v-if로 조건을 걸어주고, @click 이벤트로 조건을 바꿔주면 된다. v-if의 조건은 openModal이란 변수가 참일 때만 나타나도록 설정하고, 인덱스의 dataopenModal을 정의해준다. 인덱스 페이지가 처음 로딩될 때 나타나도록 디폴트 값을 true로 설정했다.

<script>
import PopUpView from '@/components/PopUpView.vue'
export default {
  name: 'IndexView',
  components: {
    PopUpView,
  },
  ...
  data() {
    return {
      openModal: true,
    }
  },
</script>

다음은 클릭 이벤트를 설정해준다. 여기서 중요한 것은 자식 컴포넌트에서 부모로의 데이터 전송이다. Index 페이지는 부모이고, 이 페이지에 포함된 자식 컴포넌트가 팝업창이다. 자식 컴포넌트에 있는 X 표시를 눌렀을 때, 이 이벤트가 부모인 Index 페이지에 전달되어 this.openModalfalse로 변경되어야 한다.

먼저 팝업창 컴포넌트에서 X 표시인 버튼에 @click 이벤트를 추가한다. closeModal 이벤트는 methods에 추가한다. @click="closeModalsendClose라는 이름으로 부모 페이지에 false라는 신호를 보낸다.

<template>
  ...
  <button
    type="button"
    @click="closeModal"
    class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center"
  >
    <svg
      aria-hidden="true"
      class="w-5 h-5"
      fill="currentColor"
      viewBox="0 0 20 20"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        fill-rule="evenodd"
        d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
        clip-rule="evenodd"
      ></path>
    </svg>
  </button>
  ...
</template>

<script>
export default {
  name: 'PopUpView',
  methods: {
    closeModal() {
      this.$emit('sendClose', false)
    },
  },
}
</script>

다시 인덱스 페이지로 돌아와서, @sendClose="closeModalView"v-if 옆에 추가해준다. 여기서 @ 다음의 변수는 자식 컴포넌트에서 this.$emit("sendClose", false)sendClose와 동일해야 한다. closeModalViewmethods에 추가하고, 데이터를 전송받았을 때 구현될 이벤트를 정의한다. sendClosefalse라는 데이터를 전달했으므로, closeModalView(data)에서 datafalse로 정의된다. 여기서 this.openModaldata 값으로 업데이트 해주면 이벤트 구현이 완성된다.

<template>
  <div class="w-full bg-white">
    <!-- popup window -->
    <PopUpView v-if="this.openModal == true" @sendClose="closeModalView" />
    ...
  </div>
</template>

<script>
import PopUpView from '@/components/PopUpView.vue' // 컴포넌트 불러오기
export default {
  name: 'IndexView',
  components: {
    PopUpView, // 여기에 추가해주기
  },
  ...
  methods: {
    closeModalView(data) {
      this.openModal = data
    },
  }
}
</script>

마지막으로

Vue를 사용하면, 컴포넌트 사이의 통신을 고려해야 하지만 한번 원리를 알면 통신은 어렵지 않다. 부모와 자식, 자식과 부모, 자식과 자식 컴포넌트의 통신만 할 수 있으면 웬만한 개발은 어렵지 않은 것 같다. 또한 자바스크립트에서 클릭 이벤트를 쉽게 구현할 수 있기 때문에 프론트 단을 빠르게 개발할 수 있다. 하지만.. 프론트는 하면 할 수록 어려운 것 같다 🥲

Tags:
#Vue3
#modal
#Popup window
#click event