119 lines
2.7 KiB
Vue
119 lines
2.7 KiB
Vue
<script setup lang="ts">
|
|
import { Splide } from '@splidejs/vue-splide'
|
|
import type { Splide as SplideType, ResponsiveOptions } from '@splidejs/splide'
|
|
|
|
interface Props {
|
|
autoplay?: boolean | string
|
|
arrows?: boolean
|
|
pagination?: boolean
|
|
class?: string
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
autoplay: false,
|
|
arrows: true,
|
|
pagination: true,
|
|
})
|
|
|
|
|
|
const emit = defineEmits(['mounted', 'move', 'moved', 'arrowClick'])
|
|
|
|
const options = computed((): ResponsiveOptions => {
|
|
return {
|
|
type: 'fade',
|
|
rewind: true,
|
|
perPage: 1,
|
|
perMove: 1,
|
|
speed: 600,
|
|
updateOnMove: true,
|
|
autoplay: props.autoplay,
|
|
arrows: props.arrows,
|
|
pagination: props.pagination,
|
|
classes: {
|
|
arrows: 'splide-arrows type-full',
|
|
arrow: 'splide-arrow',
|
|
prev: 'arrow-prev',
|
|
next: 'arrow-next',
|
|
pagination: 'splide-pagination-bullets type-full',
|
|
page: 'splide-pagination-bullet',
|
|
},
|
|
}
|
|
})
|
|
|
|
|
|
const handleSplideMounted = (splide: SplideType) => {
|
|
emit('mounted', splide)
|
|
splide.refresh()
|
|
|
|
// 화살표 버튼 클릭 이벤트 리스너 추가
|
|
nextTick(() => {
|
|
addArrowClickListeners(splide)
|
|
})
|
|
}
|
|
|
|
const handleMove = (
|
|
splide: SplideType,
|
|
newIndex: number,
|
|
oldIndex: number,
|
|
destIndex: number
|
|
) => {
|
|
emit('move', splide, newIndex, oldIndex, destIndex)
|
|
}
|
|
|
|
const handleMoved = (
|
|
splide: SplideType,
|
|
newIndex: number,
|
|
oldIndex: number,
|
|
destIndex: number
|
|
) => {
|
|
emit('moved', splide, newIndex, oldIndex, destIndex)
|
|
}
|
|
|
|
const handleArrowClick = (direction: 'prev' | 'next', splide: SplideType) => {
|
|
const currentIndex = splide.index
|
|
const totalSlides = splide.length
|
|
|
|
// 이동할 슬라이드 인덱스 계산
|
|
let targetIndex: number
|
|
if (direction === 'next') {
|
|
targetIndex = currentIndex + 1 >= totalSlides ? 0 : currentIndex + 1
|
|
} else {
|
|
targetIndex = currentIndex - 1 < 0 ? totalSlides - 1 : currentIndex - 1
|
|
}
|
|
|
|
emit('arrowClick', direction, targetIndex)
|
|
}
|
|
|
|
// 화살표 버튼에 클릭 이벤트 리스너 추가
|
|
const addArrowClickListeners = (splide: SplideType) => {
|
|
const prevArrow = splide.root.querySelector('.arrow-prev')
|
|
const nextArrow = splide.root.querySelector('.arrow-next')
|
|
|
|
if (prevArrow) {
|
|
prevArrow.addEventListener('click', () => handleArrowClick('prev', splide))
|
|
}
|
|
|
|
if (nextArrow) {
|
|
nextArrow.addEventListener('click', () => handleArrowClick('next', splide))
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<Splide
|
|
:options="options"
|
|
class="h-full"
|
|
@splide:mounted="handleSplideMounted"
|
|
@splide:move="handleMove"
|
|
@splide:moved="handleMoved"
|
|
>
|
|
<slot />
|
|
</Splide>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.splide:deep(.splide__track) {
|
|
@apply h-full;
|
|
}
|
|
</style>
|