112 lines
2.7 KiB
Vue
112 lines
2.7 KiB
Vue
<template>
|
|
<div v-show="showSwiper" class="relative" :class="rootClasses">
|
|
<swiper
|
|
loop-add-blank-slides
|
|
:class="sliderClasses"
|
|
:direction="direction"
|
|
:space-between="50"
|
|
:breakpoints="{
|
|
2000: { slidesPerView: 1, spaceBetween: 40 },
|
|
}"
|
|
@swiper="onSwiper"
|
|
@slide-change="onSlideChange"
|
|
>
|
|
<swiper-slide
|
|
v-for="slide in 4"
|
|
:key="slide"
|
|
class="h-full hover:cursor-pointer"
|
|
>
|
|
<slot />
|
|
</swiper-slide>
|
|
</swiper>
|
|
<div :class="counterClasses">
|
|
<div
|
|
v-for="(slide, index) in 4"
|
|
:key="index"
|
|
class="bg-black"
|
|
:style="[
|
|
'height: 3px; transition: all 0.5s;',
|
|
index === currentSlideNumber
|
|
? 'padding-top : 8px; padding-bottom: 8px; width: 16px; border-radius : 50%;'
|
|
: 'height: 3px; width: 25px;',
|
|
]"
|
|
@click="goToSlide(index), stopAutoSlide()"
|
|
></div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed, defineProps, withDefaults, onMounted } from "vue";
|
|
import { Swiper, SwiperSlide } from "swiper/vue";
|
|
import type { Swiper as swiper } from "swiper/types";
|
|
import "swiper/css";
|
|
import { twMerge } from "tailwind-merge";
|
|
import type { PTAttribs } from "./types";
|
|
|
|
const showSwiper = ref(false);
|
|
const currentSlideNumber = ref(0);
|
|
let swiperInstance: swiper | null = null;
|
|
let intervalId: NodeJS.Timeout | null = null;
|
|
|
|
const onSwiper = (swiper: swiper) => {
|
|
swiperInstance = swiper;
|
|
showSwiper.value = true;
|
|
};
|
|
|
|
const onSlideChange = (swiper: swiper) => {
|
|
currentSlideNumber.value = swiper.realIndex;
|
|
};
|
|
|
|
function startAutoSlide() {
|
|
intervalId = setInterval(() => {
|
|
const nextSlide = (currentSlideNumber.value + 1) % 4;
|
|
goToSlide(nextSlide);
|
|
}, 5000);
|
|
}
|
|
|
|
function goToSlide(index: number) {
|
|
swiperInstance?.slideTo(index);
|
|
currentSlideNumber.value = index;
|
|
}
|
|
|
|
function stopAutoSlide() {
|
|
if (intervalId !== null) {
|
|
clearInterval(intervalId);
|
|
intervalId = null;
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
startAutoSlide();
|
|
});
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
direction: "horizontal" | "vertical";
|
|
pt?: PTAttribs;
|
|
}>(),
|
|
{
|
|
direction: "horizontal",
|
|
}
|
|
);
|
|
|
|
const classes = ref({
|
|
root: { class: `` },
|
|
slider: { class: `` },
|
|
counter: {
|
|
class: `mx-auto px-6 container flex justify-between items-center h-10 cursor-pointer`,
|
|
},
|
|
} as PTAttribs);
|
|
|
|
const rootClasses = computed(() =>
|
|
twMerge(classes.value.root?.class, props.pt?.root?.class)
|
|
);
|
|
const sliderClasses = computed(() =>
|
|
twMerge(classes.value.slider?.class, props.pt?.slider?.class)
|
|
);
|
|
const counterClasses = computed(() =>
|
|
twMerge(classes.value.counter?.class, props.pt?.counter?.class)
|
|
);
|
|
</script>
|