본문 바로가기

개발/Vue

[VUE3] swiper 부드럽게 흐르는 슬라이드, 일시정지 기능 추가

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로 설정하여 콘텐츠의 크기에 맞게 슬라이드가 조정되도록 처리했다.