Swiper
카드 슬라이드가 천천히 흐르며, 일시정지/재생 버튼과 마우스를 올리면 슬라이드가 자동으로 일시정지되는 기능을 만들었다.
<template>
<div class="playSwiper-comp">
<div class="title-wrapper">
<slot name="title"></slot>
<i v-if="!playStatus" class="arrow-play" @click="controlSwiper(true)"></i>
<i v-else class="icon-pause" @click="controlSwiper(false)"></i>
</div>
<div class="contents-wrapper">
<Swiper
@swiper="onSwiper"
@mouseenter="controlSwiper(false)"
@mouseleave="controlSwiper(true)"
@touch-end="controlSwiper(null)"
class="swiper"
:modules="[Autoplay]"
slidesPerView="auto"
:autoplay="{
delay: 0,
disableOnInteraction: false,
}"
:speed="3000"
loop
loopAdditionalSlides="1"
>
<swiper-slide
v-for="item in items"
:key="item"
class="swiper-slide-content"
>
<slot name="item" v-bind="item" />
</swiper-slide>
<swiper-slide
v-for="item in items"
:key="item"
class="swiper-slide-content"
>
<slot name="item" v-bind="item" />
</swiper-slide>
</Swiper>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { Swiper, SwiperSlide } from 'swiper/vue';
import { Autoplay } from 'swiper/modules';
import 'swiper/css';
const swiperEl = ref(null);
const playStatus = ref(true);
const duration = ref(0);
const touch = ref(false);
defineProps({
items: {
type: Array,
required: true,
},
});
// 스와이퍼 로드
const onSwiper = swiper => {
swiperEl.value = swiper;
};
// 슬라이드 플레이 컨트롤
const controlSwiper = play => {
if (play === null) {
touch.value = true;
return;
}
if (play) {
if (touch.value) {
// 터치 후 플레이
setTimeout(() => {
swiperEl.value.autoplay.start();
}, 2000);
touch.value = false;
return;
}
const distance =
swiperEl.value.width * swiperEl.value.activeIndex +
swiperEl.value.getTranslate();
duration.value = distance !== 0 ? duration.value : 0;
swiperEl.value.slideTo(swiperEl.value.activeIndex, duration.value);
swiperEl.value.autoplay.start();
playStatus.value = true;
} else {
swiperEl.value.setTranslate(swiperEl.value.getTranslate()); // 즉시 멈춤
const currentSlideWidth =
swiperEl.value.slides[swiperEl.value.activeIndex].offsetWidth;
const distanceRatio = Math.abs(
(currentSlideWidth * swiperEl.value.activeIndex +
swiperEl.value.getTranslate()) /
currentSlideWidth,
);
duration.value = swiperEl.value.params.speed * distanceRatio;
swiperEl.value.autoplay.stop();
playStatus.value = false;
}
};
</script>
스와이퍼의 기본 멈춤 기능을 사용하면 슬라이드가 멈추긴 하지만, 이동이 완료된 후에야 멈추기 때문에 완전히 정지하는 데 시간이 걸린다. 이를 해결하기 위해 마우스를 올리거나 일시정지 버튼을 누르는 즉시 슬라이드가 멈추도록 controlSwiper 함수를 활용해 autoplay 멈춤 기능을 구현했다.
<style lang="scss" scoped>
.playSwiper-comp {
width: 100%;
.title-wrapper {
margin: auto;
margin-bottom: 50px;
width: calc(100% - 40px);
display: flex;
justify-content: space-between;
align-items: flex-end;
i {
cursor: pointer;
}
@media screen and (max-width: 768px) {
margin-bottom: 30px;
}
}
.contents-wrapper {
margin: 0 auto;
@media screen and (max-width: 768px) {
margin: 0 -16px;
}
.swiper {
width: 100%;
:deep(.swiper-wrapper) {
transition-timing-function: linear !important;
}
.swiper-slide-content {
width: auto; /* Adjust width dynamically to match slot content */
display: inline-block; /* Ensures content doesn't stretch full width */
}
}
}
}
</style>
스와이퍼가 부드럽게 흐르도록 하기 위해 swiper-wrapper 클래스에 transition-timing-function: linear !important;를 추가했다.
또한, 스와이퍼 안의 콘텐츠 너비를 동적으로 조정하기 위해 width를 auto로 설정하여 콘텐츠의 크기에 맞게 슬라이드가 조정되도록 처리했다.
'개발 > Vue' 카테고리의 다른 글
[vue-dompurify-html] a태그 새 창 열기 (1) | 2024.10.16 |
---|---|
[VUE] Scoped 스타일에서 자식 요소 스타일링 : deep() (1) | 2024.10.07 |
[VUE3 router] Navigation Guards로 로그인 페이지 이동 처리 (1) | 2024.07.23 |
[Pinia] Setup Stores 방식에 pinia-plugin-persistedstate 사용하기 (0) | 2024.07.16 |
[Vite] webpack에서 vite로 전환하기 (0) | 2024.05.27 |