| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- <template>
- <Teleport to="body">
- <Transition name="dealer--popup--fade">
- <div
- v-if="isOpen"
- class="dealer--popup--overlay type2"
- @click.self="handleClose"
- role="dialog"
- aria-modal="true"
- :aria-labelledby="dealerData ? 'dealer-name' : undefined"
- >
- <div class="dealer--popup--container" ref="popupRef">
- <!-- 닫기 버튼 -->
- <button
- class="dealer--popup--close"
- @click="handleClose"
- aria-label="팝업 닫기"
- >
- <span class="close--icon"></span>
- </button>
- <!-- 팝업 내용 -->
- <div v-if="dealerData" class="dealer--popup--content">
- <div class="dealer--thumb--wrap">
- <!-- imgsrc2가 있으면 스와이퍼 사용 -->
- <template v-if="dealerData.imgsrc2">
- <Swiper
- :modules="[SwiperNavigation, SwiperPagination]"
- :navigation="true"
- :loop="true"
- :spaceBetween="0"
- :slidesPerView="1"
- class="dealer--swiper"
- >
- <SwiperSlide v-for="(image, index) in dealerImages" :key="index">
- <img :src="image" :alt="`딜러 이미지 ${index + 1}`" />
- </SwiperSlide>
- </Swiper>
- </template>
- <!-- imgsrc2가 없으면 단일 이미지 -->
- <template v-else>
- <img :src="dealerData.imgsrc" alt="딜러 이미지" />
- </template>
- </div>
- <div class="dealer--infos--wrap">
- <!-- 헤더 -->
- <div class="dealer--popup--header">
- <h2 id="dealer-name" class="dealer--name">
- {{ dealerData.fullName }}
- </h2>
- </div>
- <!-- 정보 섹션 -->
- <div class="dealer--popup--body">
- <!-- 소개 -->
- <div v-if="dealerData.desc" class="dealer--info--section">
- <div class="info--label desc--type">{{ dealerData.desc }}
- </div>
- </div>
- <!-- 강조 문구 -->
- <div v-if="dealerData.strongDesc"><b>{{ dealerData.strongDesc }}</b></div>
- <!-- 주소 -->
- <div v-if="dealerData.address" class="dealer--info--section">
- <div class="info--label">주소: {{ dealerData.address }}</div>
- </div>
- <!-- 전화번호 -->
- <div v-if="dealerData.phone" class="dealer--info--section">
- <div class="info--label">Tel: {{ dealerData.phone }}</div>
- </div>
- <!-- 팩스 -->
- <div v-if="dealerData.fax" class="dealer--info--section">
- <div class="info--label">Fax: {{ dealerData.fax }}</div>
- </div>
- <!-- A/S -->
- <div v-if="dealerData.as" class="dealer--info--section">
- <div class="info--label">A/S: {{ dealerData.as }}</div>
- </div>
- <!-- 추가내용 -->
- <div v-if="dealerData.add1" class="dealer--info--section ">
- <div class="info--label">
- {{ dealerData.add1 }}: {{ dealerData.adddesc1 }}
- </div>
- </div>
- <!-- 추가내용 -->
- <div v-if="dealerData.add2" class="dealer--info--section">
- <div class="info--label">
- {{ dealerData.add2 }}: {{ dealerData.adddesc2 }}
- </div>
- </div>
- <!-- 추가내용 -->
- <div v-if="dealerData.add3" class="dealer--info--section">
- <div class="info--label">
- {{ dealerData.add3 }}: {{ dealerData.adddesc3 }}
- </div>
- </div>
- <!-- 추가내용 -->
- <div v-if="dealerData.addtext" class="dealer--info--section">
- <div class="info--label">
- {{ dealerData.addtext }}
- </div>
- </div>
- <!-- 웹사이트 -->
- <div v-if="dealerData.website" class="dealer--info--section">
- <div class="info--label">
- <NuxtLink
- :to="dealerData.website"
- target="_blank"
- class="light--gray--btn mt--20 ft--14"
- >
- {{ dealerData.websitetitle }}
- </NuxtLink>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!-- 데이터가 없을 때 -->
- <div v-else class="dealer--popup--empty">
- <p>딜러 정보를 불러올 수 없습니다.</p>
- </div>
- </div>
- </div>
- </Transition>
- </Teleport>
- </template>
- <script setup>
- import { ref, watch, onMounted, onUnmounted, computed } from "vue";
- import { Navigation as SwiperNavigation, Pagination as SwiperPagination } from "swiper/modules";
- import { Swiper, SwiperSlide } from "swiper/vue";
- import "swiper/css";
- import "swiper/css/navigation";
- import "swiper/css/pagination";
- const props = defineProps({
- isOpen: {
- type: Boolean,
- required: true,
- default: false,
- },
- dealerData: {
- type: Object,
- default: null,
- },
- });
- const emit = defineEmits(["close"]);
- const popupRef = ref(null);
- // 딜러 이미지 배열 생성 (imgsrc, imgsrc2, imgsrc3, ... 동적 처리)
- const dealerImages = computed(() => {
- if (!props.dealerData) return [];
- const images = [];
- let index = 1;
- // imgsrc부터 시작
- if (props.dealerData.imgsrc) {
- images.push(props.dealerData.imgsrc);
- }
- // imgsrc2, imgsrc3, ... 숫자가 있는 이미지들 추가
- while (props.dealerData[`imgsrc${index + 1}`]) {
- images.push(props.dealerData[`imgsrc${index + 1}`]);
- index++;
- }
- return images;
- });
- const handleClose = () => {
- emit("close");
- };
- // ESC 키로 팝업 닫기
- const handleEscKey = (event) => {
- if (event.key === "Escape" && props.isOpen) {
- handleClose();
- }
- };
- // body 스크롤 제어
- const toggleBodyScroll = (disable) => {
- if (disable) {
- document.body.style.overflow = "hidden";
- } else {
- document.body.style.overflow = "";
- }
- };
- // 포커스 트랩
- const handleFocusTrap = (event) => {
- if (!props.isOpen || !popupRef.value) return;
- const focusableElements = popupRef.value.querySelectorAll(
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
- );
- const firstElement = focusableElements[0];
- const lastElement = focusableElements[focusableElements.length - 1];
- if (event.key === "Tab") {
- if (event.shiftKey && document.activeElement === firstElement) {
- event.preventDefault();
- lastElement.focus();
- } else if (!event.shiftKey && document.activeElement === lastElement) {
- event.preventDefault();
- firstElement.focus();
- }
- }
- };
- // isOpen 상태 감지
- watch(
- () => props.isOpen,
- (newValue) => {
- toggleBodyScroll(newValue);
- if (newValue) {
- // 팝업이 열릴 때 첫 번째 포커스 가능한 요소에 포커스
- setTimeout(() => {
- if (popupRef.value) {
- const firstFocusable = popupRef.value.querySelector(
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
- );
- if (firstFocusable) {
- firstFocusable.focus();
- }
- }
- }, 100);
- }
- }
- );
- onMounted(() => {
- document.addEventListener("keydown", handleEscKey);
- document.addEventListener("keydown", handleFocusTrap);
- });
- onUnmounted(() => {
- document.removeEventListener("keydown", handleEscKey);
- document.removeEventListener("keydown", handleFocusTrap);
- toggleBodyScroll(false);
- });
- </script>
|