Root of the composable Swiper carousel; owns the Swiper instance, deferred image loading and the reveal.
import SwiperRootPrimitive from "@wikicasa-dev/components/generic/carousel/Primitive/SwiperRootPrimitive";
Build a custom carousel from parts when SwiperCarousel isn't enough: a photo gallery that downloads only the photos near the current one, a thumbnail strip, your own arrow buttons. The parts:
SwiperRootPrimitive: creates and destroys the Swiper instance fromswiper-options(any Swiper option exceptpagination/navigation, e.g.slidesPerView,loop,rewind,keyboard,autoplay,zoom,breakpoints). Slots: default (the parts below),#placeholder(laid over the carousel until it is ready),#thumbs(rendered outside the clipped.swiperbox).SwiperPrimitive: the slide track; put the slides in it.SwiperSlide(any content) orSwiperSlideImagePrimitive(one image, optionally deferred withlazy).SwiperPaginationPrimitive,SwiperNavigationPrimitive: bullets/fraction and arrows, next toSwiperPrimitive.SwiperThumbnailPrimitive: thumbnail strip linked to the carousel, in#thumbs.
The carousel stays at opacity: 0 (space reserved) until Swiper has started and the active slide's images have loaded (6s at most), then appears. Images with data-src (or SwiperSlideImagePrimitive with lazy) load only when their slide is on screen or within preload-count slides of it.
Usage
<script setup lang="ts">
import SwiperRootPrimitive from "@wikicasa-dev/components/generic/carousel/Primitive/SwiperRootPrimitive";
import SwiperPrimitive from "@wikicasa-dev/components/generic/carousel/Primitive/SwiperPrimitive";
import SwiperSlideImagePrimitive from "@wikicasa-dev/components/generic/carousel/Primitive/SwiperSlideImagePrimitive";
import SwiperPaginationPrimitive from "@wikicasa-dev/components/generic/carousel/Primitive/SwiperPaginationPrimitive";
import SwiperNavigationPrimitive from "@wikicasa-dev/components/generic/carousel/Primitive/SwiperNavigationPrimitive";
import SwiperThumbnailPrimitive from "@wikicasa-dev/components/generic/carousel/Primitive/SwiperThumbnailPrimitive";
const photos = [
{ src: "/img/villa-1.jpg", alt: "Villa a Lucca, facciata" },
{ src: "/img/villa-2.jpg", alt: "Villa a Lucca, soggiorno" },
{ src: "/img/villa-3.jpg", alt: "Villa a Lucca, giardino" },
];
</script>
<template>
<SwiperRootPrimitive class="gallery" :preload-count="1" :swiper-options="{ slidesPerView: 1, keyboard: { enabled: true } }">
<SwiperPrimitive>
<SwiperSlideImagePrimitive
v-for="(p, i) in photos" :key="p.src" :src="p.src" :alt="p.alt" :width="800" :height="600"
:lazy="i > 0" :fetchpriority="i === 0 ? 'high' : 'low'" img-classes="gallery__img"
/>
</SwiperPrimitive>
<SwiperPaginationPrimitive :options="{ type: 'fraction' }" />
<SwiperNavigationPrimitive />
<template #thumbs>
<SwiperThumbnailPrimitive :swiper-options="{ slidesPerView: 4, spaceBetween: 8, freeMode: true }">
<SwiperSlideImagePrimitive v-for="p in photos" :key="p.src" :src="p.src" :alt="p.alt" lazy img-classes="gallery__thumb" />
</SwiperThumbnailPrimitive>
</template>
</SwiperRootPrimitive>
</template>
<style scoped>
.gallery :deep(.gallery__img) { width: 100%; height: 480px; object-fit: cover; }
.gallery :deep(.gallery__thumb) { width: 80px; height: 80px; object-fit: cover; border-radius: 8px; }
</style>
Do / Don't
- Do render pagination, navigation and thumbnail primitives unconditionally: they register with the root while it is being created; adding one later (
v-ifturning true) has no effect. - Do give the first, visible slide's image a real
src(notlazy) andfetchpriority="high"; defer the rest. - Don't change
root-classesafter mount (Swiper's own classes on that element would be wiped); put toggling classes on the component itself (classlands on an outer wrapper). - Don't listen for
@clickhere (never emitted); put it onSwiperPrimitive.inithands you the Swiper instance (also exposed asswiper), handy for your own prev/next buttons:swiper.slidePrev(). - Treat
swiper-optionsas fixed; use the exposedupdateSlidesPerView(n)to change slides per view. - Swiper's stylesheets load with Swiper after mount. A server-rendered carousel whose pre-start layout must already be right imports them itself, as wikicasa-nuxt does:
@import "@wikicasa-dev/components/css/swiper-swiper";(plusswiper-zoom).
Styling hooks
Same Swiper CSS variables as SwiperCarousel (--swiper-pagination-*, --swiper-navigation-*), set with :deep() from a wrapper. The active thumbnail slide has .swiper-slide-thumb-active.
API
Generated from the component's types. Do not edit by hand.
Props
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
rootClasses |
ClassTypeProp |
|||
swiperOptions |
SwiperRootPrimitiveProps |
|||
preloadCount |
number |
Slides to promote beyond each edge of the visible window. Falls back to swiperOptions.lazyPreloadPrevNext when unset, which is how this was configured before and stays supported - but that option's documented job is Swiper's own loading="lazy" preloading, which these slides do not use. Prefer this prop. |
Events
| Name | Payload |
|---|---|
click |
|
moved |
[{ activeIndex: number; }] |
init |
[Swiper] |
v-model
None.
Slots
| Name | Slot props |
|---|---|
default |
|
placeholder |
|
thumbs |
Exposed (template ref)
| Name | Type |
|---|---|
swiper |
Nullable<Swiper> |
updateSlidesPerView |
(value: number) => void |