carousel
Carousel with thumbnail navigation
Carousel with thumbnail navigation
Загрузка превью…
src/carousel/c-carousel-9.vue
<script setup lang="ts">
import { ref, watch } from "vue"
import type { EmblaCarouselType } from "embla-carousel"
import { Carousel, CarouselContent, CarouselItem } from "@/components/ui/carousel"
import { cn } from "@/lib/utils"
const PIXEL = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs="
const ITEMS_COUNT = 10
const items = Array.from({ length: ITEMS_COUNT }, (_, index) => index)
const mainApi = ref<EmblaCarouselType>()
const thumbApi = ref<EmblaCarouselType>()
const selectedIndex = ref(1)
const bound = ref(false)
function onThumbClick(index: number) {
if (!mainApi.value || !thumbApi.value) return
mainApi.value.scrollTo(index)
}
watch(
[mainApi, thumbApi],
([main, thumb]) => {
if (!main || !thumb || bound.value) return
bound.value = true
const onSelect = () => {
if (!mainApi.value || !thumbApi.value) return
const index = mainApi.value.selectedScrollSnap()
selectedIndex.value = index
thumbApi.value.scrollTo(index)
}
onSelect()
main.on("select", onSelect)
main.on("reInit", onSelect)
},
{ immediate: true }
)
</script>
<template>
<div class="flex w-full max-w-md flex-col gap-3 p-4">
<Carousel :set-api="(api) => (mainApi = api)" :opts="{ startIndex: 1, duration: 0 }" class="w-full">
<CarouselContent>
<CarouselItem v-for="index in items" :key="index">
<div class="bg-muted relative aspect-video overflow-hidden rounded-xl">
<img :src="PIXEL" :alt="`Slide ${index + 1}`" width="1000" height="800" class="h-full w-full object-cover" />
</div>
</CarouselItem>
</CarouselContent>
</Carousel>
<Carousel :set-api="(api) => (thumbApi = api)" :opts="{ containScroll: 'keepSnaps', dragFree: true, duration: 0 }" class="w-full">
<CarouselContent class="-ml-2 flex-row">
<CarouselItem
v-for="index in items"
:key="index"
class="basis-1/5 cursor-pointer pl-2 sm:basis-1/6"
@click="onThumbClick(index)"
>
<div
:class="
cn(
'relative aspect-square overflow-hidden rounded-lg border-2 transition-all',
index === selectedIndex ? 'border-primary opacity-100' : 'border-transparent opacity-40 hover:opacity-70'
)
"
>
<img :src="PIXEL" :alt="`Thumb ${index + 1}`" width="400" height="400" class="h-full w-full object-cover" />
</div>
</CarouselItem>
</CarouselContent>
</Carousel>
</div>
</template>