티스토리 뷰

지난 글에서는 페이지 이동할 때 transition을 적용했다면 이번 글에서는 모달창이 나올 때의 transition을 적용해보겠다. 모달창의 경우에는 <teleport>태그를 활용하여 DOM상에서 등록되는 위치를 분리해준다.

// index.html
    <body>
      <div id="app"></div>
      <div id="desktop-modal"></div>
    </body>
// TeleportModal.vue - template
  <teleport to="#desktop-modal">
    <div class="modal">
      <transition name="slide-up" appear>
        <div class="modal-content" ref="modalRef">
          <div>
            <div>
              <h1>This is Modal</h1>
              <button @click="modalStore.closeModal()">Close</button>
            </div>
          </div>
        </div>
      </transition>
    </div>
  </teleport>

모달창이 등장하는 transition은 아래에서 위로 올라오는 slide-up을 사용할 것이다. 여기서 버그인지는 모르겠으나 slide-up-leave는 작동하지 않는 문제가 발생했다. 추정하기로는 <TeleportModal v-if="isModalShow" /> 처럼 v-if로 조건부 렌더링을 걸어버리면 isModalShowfalse가 되어버리자마자 DOM에서 사라지게 되어 transition-time을 무시해버리는 것 같다. 이 문제를 해결하기 위해서 modalStore.closeModal()이 호출될 때는 modal-contenthide라는 별도의 css transform을 정의해서 사라지게 만들었다.

// TeleportModal - style
.modal {
  position: fixed;
  inset: 0px;
  z-index: 10;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: rgba(0, 0, 0, 0.5);
}
.modal .modal-content {
  width: 50vh;
  height: 300px;
  background-color: white;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* 위에서 올라오는 동작 ON */
.slide-up-enter-from {
  transform: translateY(100%);
}
.slide-up-enter-active {
  transition: transform 0.2s ease-in-out;
}

.modal-content.hide {
  transform: translateY(100%);
  transition: transform 0.2s ease-in-out;
}
// stores/modal.js
import { defineStore } from "pinia";

export const useModalStore = defineStore("modal", {
  state: () => {
    return {
      modal: false
    };
  },
  actions: {
    openModal() {
      this.modal = true;
    },
    closeModal() {
      const modalEl = document.querySelector(
        "#desktop-modal .modal .modal-content"
      );
      if (modalEl) {
        modalEl.classList.add("hide");
        const toId = setTimeout(() => {
          this.modal = false;
          clearTimeout(toId);
        }, 200);
      }
    }
  }
});

다음 글에서는 현재 떠 있는 모달창이 닫히는 기능을 구현해보도록 하겠다.

댓글