用法
使用 Carousel 组件在轮播图中显示项目列表。
<script setup lang="ts">
const items = [
'https://picsum.photos/640/640?random=1',
'https://picsum.photos/640/640?random=2',
'https://picsum.photos/640/640?random=3',
'https://picsum.photos/640/640?random=4',
'https://picsum.photos/640/640?random=5',
'https://picsum.photos/640/640?random=6'
]
</script>
<template>
<UCarousel
v-slot="{ item }"
loop
arrows
:autoplay="{ delay: 2000 }"
wheel-gestures
:prev="{ variant: 'solid' }"
:next="{ variant: 'solid' }"
:items="items"
:ui="{
item: 'basis-1/3 ps-0',
prev: 'sm:start-8',
next: 'sm:end-8',
container: 'ms-0'
}"
>
<img :src="item" width="320" height="320">
</UCarousel>
</template>
项
将 items prop 作为数组使用,并使用默认插槽渲染每个项目
<script setup lang="ts">
const items = [
'https://picsum.photos/640/640?random=1',
'https://picsum.photos/640/640?random=2',
'https://picsum.photos/640/640?random=3',
'https://picsum.photos/640/640?random=4',
'https://picsum.photos/640/640?random=5',
'https://picsum.photos/640/640?random=6'
]
</script>
<template>
<UCarousel v-slot="{ item }" :items="items" class="w-full max-w-xs mx-auto">
<img :src="item" width="320" height="320" class="rounded-lg" loading="lazy">
</UCarousel>
</template>
您还可以传入一个包含以下属性的对象数组
class?: anyui?: { item?: ClassNameValue }
你可以通过在 item 上使用basis / width工具类来控制可见项目的数量
<script setup lang="ts">
const items = [
'https://picsum.photos/468/468?random=1',
'https://picsum.photos/468/468?random=2',
'https://picsum.photos/468/468?random=3',
'https://picsum.photos/468/468?random=4',
'https://picsum.photos/468/468?random=5',
'https://picsum.photos/468/468?random=6'
]
</script>
<template>
<UCarousel v-slot="{ item }" :items="items" :ui="{ item: 'basis-1/3' }">
<img :src="item" width="234" height="234" class="rounded-lg" loading="lazy">
</UCarousel>
</template>
Orientation
使用 orientation prop 更改进度条的方向。默认为 horizontal(水平)。
<script setup lang="ts">
const items = [
'https://picsum.photos/640/640?random=1',
'https://picsum.photos/640/640?random=2',
'https://picsum.photos/640/640?random=3',
'https://picsum.photos/640/640?random=4',
'https://picsum.photos/640/640?random=5',
'https://picsum.photos/640/640?random=6'
]
</script>
<template>
<UCarousel
v-slot="{ item }"
orientation="vertical"
:items="items"
:ui="{ container: 'h-[336px]' }"
class="w-full max-w-xs mx-auto"
>
<img :src="item" width="320" height="320" class="rounded-lg" loading="lazy">
</UCarousel>
</template>
height(高度)。箭头
使用 arrows prop 显示上一个和下一个按钮。
<script setup lang="ts">
const items = [
'https://picsum.photos/640/640?random=1',
'https://picsum.photos/640/640?random=2',
'https://picsum.photos/640/640?random=3',
'https://picsum.photos/640/640?random=4',
'https://picsum.photos/640/640?random=5',
'https://picsum.photos/640/640?random=6'
]
</script>
<template>
<UCarousel v-slot="{ item }" arrows :items="items" class="w-full max-w-xs mx-auto">
<img :src="item" width="320" height="320" class="rounded-lg" loading="lazy">
</UCarousel>
</template>
上一个 / 下一个
使用 prev 和 next props,通过任何 Button props 来自定义上一个和下一个按钮。
<script setup lang="ts">
const items = [
'https://picsum.photos/640/640?random=1',
'https://picsum.photos/640/640?random=2',
'https://picsum.photos/640/640?random=3',
'https://picsum.photos/640/640?random=4',
'https://picsum.photos/640/640?random=5',
'https://picsum.photos/640/640?random=6'
]
</script>
<template>
<UCarousel
v-slot="{ item }"
arrows
:prev="{ color: 'primary' }"
:next="{ variant: 'solid' }"
:items="items"
class="w-full max-w-xs mx-auto"
>
<img :src="item" width="320" height="320" class="rounded-lg" loading="lazy">
</UCarousel>
</template>
上一个 / 下一个图标
使用 prev-icon 和 next-icon props 来自定义按钮 Icon。默认为 i-lucide-arrow-left / i-lucide-arrow-right。
<script setup lang="ts">
defineProps<{
prevIcon?: string
nextIcon?: string
}>()
const items = [
'https://picsum.photos/640/640?random=1',
'https://picsum.photos/640/640?random=2',
'https://picsum.photos/640/640?random=3',
'https://picsum.photos/640/640?random=4',
'https://picsum.photos/640/640?random=5',
'https://picsum.photos/640/640?random=6'
]
</script>
<template>
<UCarousel
v-slot="{ item }"
arrows
:prev-icon="prevIcon"
:next-icon="nextIcon"
:items="items"
class="w-full max-w-xs mx-auto"
>
<img :src="item" width="320" height="320" class="rounded-lg" loading="lazy">
</UCarousel>
</template>
圆点
使用 dots prop 显示圆点列表以滚动到特定幻灯片。
<script setup lang="ts">
const items = [
'https://picsum.photos/640/640?random=1',
'https://picsum.photos/640/640?random=2',
'https://picsum.photos/640/640?random=3',
'https://picsum.photos/640/640?random=4',
'https://picsum.photos/640/640?random=5',
'https://picsum.photos/640/640?random=6'
]
</script>
<template>
<UCarousel v-slot="{ item }" dots :items="items" class="w-full max-w-xs mx-auto">
<img :src="item" width="320" height="320" class="rounded-lg" loading="lazy">
</UCarousel>
</template>
圆点的数量基于视图中显示的幻灯片数量
<script setup lang="ts">
const items = [
'https://picsum.photos/640/640?random=1',
'https://picsum.photos/640/640?random=2',
'https://picsum.photos/640/640?random=3',
'https://picsum.photos/640/640?random=4',
'https://picsum.photos/640/640?random=5',
'https://picsum.photos/640/640?random=6'
]
</script>
<template>
<UCarousel v-slot="{ item }" dots :items="items" :ui="{ item: 'basis-1/3' }">
<img :src="item" width="320" height="320" class="rounded-lg" loading="lazy">
</UCarousel>
</template>
插件
Carousel 组件实现了官方的Embla Carousel 插件.
自动播放 (Autoplay)
此插件用于为 Embla Carousel 扩展自动播放功能。
使用 autoplay prop 作为布尔值或对象来配置自动播放插件.
<script setup lang="ts">
const items = [
'https://picsum.photos/468/468?random=1',
'https://picsum.photos/468/468?random=2',
'https://picsum.photos/468/468?random=3',
'https://picsum.photos/468/468?random=4',
'https://picsum.photos/468/468?random=5',
'https://picsum.photos/468/468?random=6'
]
</script>
<template>
<UCarousel
v-slot="{ item }"
loop
arrows
dots
:autoplay="{ delay: 2000 }"
:items="items"
:ui="{ item: 'basis-1/3' }"
>
<img :src="item" width="234" height="234" class="rounded-lg" loading="lazy">
</UCarousel>
</template>
loop prop 实现无限循环轮播。自动滚动 (Auto Scroll)
此插件用于为 Embla Carousel 扩展自动滚动功能。
使用 auto-scroll prop 作为布尔值或对象来配置自动滚动插件.
<script setup lang="ts">
const items = [
'https://picsum.photos/468/468?random=1',
'https://picsum.photos/468/468?random=2',
'https://picsum.photos/468/468?random=3',
'https://picsum.photos/468/468?random=4',
'https://picsum.photos/468/468?random=5',
'https://picsum.photos/468/468?random=6'
]
</script>
<template>
<UCarousel
v-slot="{ item }"
loop
dots
arrows
auto-scroll
:items="items"
:ui="{ item: 'basis-1/3' }"
>
<img :src="item" width="234" height="234" class="rounded-lg" loading="lazy">
</UCarousel>
</template>
loop prop 实现无限循环轮播。自动高度 (Auto Height)
此插件用于为 Embla Carousel 扩展自动高度功能。它会更改轮播容器的高度以适应视图中最高幻灯片的高度。
使用 auto-height prop 作为布尔值或对象来配置自动高度插件.
<script setup lang="ts">
const items = [
'https://picsum.photos/640/640?random=1',
'https://picsum.photos/640/320?random=2',
'https://picsum.photos/640/640?random=3',
'https://picsum.photos/640/320?random=4',
'https://picsum.photos/640/640?random=5',
'https://picsum.photos/640/320?random=6'
]
</script>
<template>
<UCarousel
v-slot="{ item }"
auto-height
arrows
dots
:items="items"
:ui="{
container: 'transition-[height]',
controls: 'absolute -top-8 inset-x-12',
dots: '-top-7',
dot: 'w-6 h-1'
}"
class="w-full max-w-xs mx-auto"
>
<img :src="item" width="320" height="320" class="rounded-lg" loading="lazy">
</UCarousel>
</template>
transition-[height] 类来设置高度变化的动画。类名 (Class Names)
Class Names 是 Embla Carousel 的类名切换实用插件,使你能够自动切换轮播图上的类名。
使用 class-names prop 作为布尔值或对象来配置类名插件.
<script setup lang="ts">
const items = [
'https://picsum.photos/528/528?random=1',
'https://picsum.photos/528/528?random=2',
'https://picsum.photos/528/528?random=3',
'https://picsum.photos/528/528?random=4',
'https://picsum.photos/528/528?random=5',
'https://picsum.photos/528/528?random=6'
]
</script>
<template>
<UCarousel
v-slot="{ item }"
class-names
arrows
:items="items"
:ui="{
item: 'basis-[70%] transition-opacity [&:not(.is-snapped)]:opacity-10'
}"
class="mx-auto max-w-sm"
>
<img :src="item" width="264" height="264" class="rounded-lg" loading="lazy">
</UCarousel>
</template>
item 上添加了 transition-opacity [&:not(.is-snapped)]:opacity-10 类来设置不透明度变化的动画。淡入淡出 (Fade)
此插件用于将 Embla Carousel 的滚动功能替换为淡入淡出过渡。
使用 fade prop 作为布尔值或对象来配置淡入淡出插件.
<script setup lang="ts">
const items = [
'https://picsum.photos/640/640?random=1',
'https://picsum.photos/640/640?random=2',
'https://picsum.photos/640/640?random=3',
'https://picsum.photos/640/640?random=4',
'https://picsum.photos/640/640?random=5',
'https://picsum.photos/640/640?random=6'
]
</script>
<template>
<UCarousel
v-slot="{ item }"
fade
arrows
dots
:items="items"
class="w-full max-w-xs mx-auto"
>
<img :src="item" width="320" height="320" class="rounded-lg" loading="lazy">
</UCarousel>
</template>
滚轮手势 (Wheel Gestures)
此插件用于为 Embla Carousel 扩展使用鼠标/触控板滚轮导航轮播图的能力。
使用 wheel-gestures prop 作为布尔值或对象来配置滚轮手势插件.
<script setup lang="ts">
const items = [
'https://picsum.photos/468/468?random=1',
'https://picsum.photos/468/468?random=2',
'https://picsum.photos/468/468?random=3',
'https://picsum.photos/468/468?random=4',
'https://picsum.photos/468/468?random=5',
'https://picsum.photos/468/468?random=6'
]
</script>
<template>
<UCarousel
v-slot="{ item }"
loop
wheel-gestures
:items="items"
:ui="{ item: 'basis-1/3' }"
>
<img :src="item" width="234" height="234" class="rounded-lg" loading="lazy">
</UCarousel>
</template>
示例
带有缩略图
您可以使用emblaApi函数scrollTo在轮播图下方显示缩略图,允许你导航到特定幻灯片。
<script setup lang="ts">
const items = [
'https://picsum.photos/640/640?random=1',
'https://picsum.photos/640/640?random=2',
'https://picsum.photos/640/640?random=3',
'https://picsum.photos/640/640?random=4',
'https://picsum.photos/640/640?random=5',
'https://picsum.photos/640/640?random=6'
]
const carousel = useTemplateRef('carousel')
const activeIndex = ref(0)
function onClickPrev() {
activeIndex.value--
}
function onClickNext() {
activeIndex.value++
}
function onSelect(index: number) {
activeIndex.value = index
}
function select(index: number) {
activeIndex.value = index
carousel.value?.emblaApi?.scrollTo(index)
}
</script>
<template>
<div class="flex-1 w-full">
<UCarousel
ref="carousel"
v-slot="{ item }"
arrows
:items="items"
:prev="{ onClick: onClickPrev }"
:next="{ onClick: onClickNext }"
class="w-full max-w-xs mx-auto"
@select="onSelect"
>
<img :src="item" width="320" height="320" class="rounded-lg" loading="lazy">
</UCarousel>
<div class="flex gap-1 justify-between pt-4 max-w-xs mx-auto">
<div
v-for="(item, index) in items"
:key="index"
class="size-11 opacity-25 hover:opacity-100 transition-opacity"
:class="{ 'opacity-100': activeIndex === index }"
@click="select(index)"
>
<img :src="item" width="44" height="44" class="rounded-lg" loading="lazy">
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, useTemplateRef } from 'vue'
const items = [
'https://picsum.photos/640/640?random=1',
'https://picsum.photos/640/640?random=2',
'https://picsum.photos/640/640?random=3',
'https://picsum.photos/640/640?random=4',
'https://picsum.photos/640/640?random=5',
'https://picsum.photos/640/640?random=6'
]
const carousel = useTemplateRef('carousel')
const activeIndex = ref(0)
function onClickPrev() {
activeIndex.value--
}
function onClickNext() {
activeIndex.value++
}
function onSelect(index: number) {
activeIndex.value = index
}
function select(index: number) {
activeIndex.value = index
carousel.value?.emblaApi?.scrollTo(index)
}
</script>
<template>
<div class="flex-1 w-full">
<UCarousel
ref="carousel"
v-slot="{ item }"
arrows
:items="items"
:prev="{ onClick: onClickPrev }"
:next="{ onClick: onClickNext }"
class="w-full max-w-xs mx-auto"
@select="onSelect"
>
<img :src="item" width="320" height="320" class="rounded-lg" loading="lazy">
</UCarousel>
<div class="flex gap-1 justify-between pt-4 max-w-xs mx-auto">
<div
v-for="(item, index) in items"
:key="index"
class="size-11 opacity-25 hover:opacity-100 transition-opacity"
:class="{ 'opacity-100': activeIndex === index }"
@click="select(index)"
>
<img :src="item" width="44" height="44" class="rounded-lg" loading="lazy">
</div>
</div>
</div>
</template>
API
属性
| 属性 | 默认值 | 类型 |
|---|---|---|
as | 'div' | any此组件应渲染为的元素或组件。 |
prev | { size: 'md', color: 'neutral', variant: 'link' } | Omit<ButtonProps, LinkPropsKeys>启用箭头时配置上一个按钮。 |
prevIcon | appConfig.ui.icons.arrowLeft | any显示在上一个按钮中的图标。 |
next | { size: 'md', color: 'neutral', variant: 'link' } | Omit<ButtonProps, LinkPropsKeys>启用箭头时配置下一个按钮。 |
nextIcon | appConfig.ui.icons.arrowRight | any显示在下一个按钮中的图标。 |
arrows | false | boolean显示用于滚动轮播图的上一个和下一个按钮。 |
dots | false | boolean显示用于滚动到特定幻灯片的圆点。 |
orientation | 'horizontal' | "vertical" | "horizontal"轮播图的方向。 |
items | T[] | |
autoplay | false | boolean | Partial<CreateOptionsType<OptionsType>>启用自动播放插件 |
autoScroll | false | boolean | Partial<CreateOptionsType<OptionsType>>启用自动滚动插件 |
autoHeight | false | boolean | Partial<CreateOptionsType<{ active: boolean; breakpoints: { [key: string]: Omit<Partial<any>, "breakpoints">; }; }>>启用自动高度插件 |
classNames | false | boolean | Partial<CreateOptionsType<OptionsType>>启用类名插件 |
fade | false | boolean | Partial<CreateOptionsType<{ active: boolean; breakpoints: { [key: string]: Omit<Partial<any>, "breakpoints">; }; }>>启用淡入淡出插件 |
wheelGestures | false | boolean | WheelGesturesPluginOptions启用滚轮手势插件 |
align | 'center' | "start" | "center" | "end" | (viewSize: number, snapSize: number, index: number): number |
containScroll | 'trimSnaps' | false | "trimSnaps" | "keepSnaps" |
slidesToScroll | 1 | number | "auto" |
dragFree | false | boolean |
dragThreshold | 10 | number |
inViewThreshold | 0 | number | number[] |
循环 | false | boolean |
skipSnaps | false | boolean |
duration | 25 | number |
startIndex | 0 | number |
watchDrag | true | false | true | (emblaApi: EmblaCarouselType, evt: PointerEventType): boolean | void |
watchResize | true | false | true | (emblaApi: EmblaCarouselType, entries: ResizeObserverEntry[]): boolean | void |
watchSlides | true | false | true | (emblaApi: EmblaCarouselType, mutations: MutationRecord[]): boolean | void |
watchFocus | true | false | true | (emblaApi: EmblaCarouselType, evt: FocusEvent): boolean | void |
active | true | boolean |
breakpoints | {} | { [key: string]: Omit<Partial<CreateOptionsType<{ align: AlignmentOptionType; axis: AxisOptionType; container: string | HTMLElement | null; slides: string | HTMLElement[] | NodeListOf<HTMLElement> | null; containScroll: ScrollContainOptionType; direction: AxisDirectionOptionType; slidesToScroll: SlidesToScrollOptionType; dragFree: boolean; dragThreshold: number; inViewThreshold: number | number[] | undefined; loop: boolean; skipSnaps: boolean; duration: number; startIndex: number; watchDrag: DragHandlerOptionType; watchResize: ResizeHandlerOptionType; watchSlides: SlidesHandlerOptionType; watchFocus: FocusHandlerOptionType; }>>, "breakpoints">; } |
ui | { root?: ClassNameValue; viewport?: ClassNameValue; container?: ClassNameValue; item?: ClassNameValue; controls?: ClassNameValue; arrows?: ClassNameValue; prev?: ClassNameValue; next?: ClassNameValue; dots?: ClassNameValue; dot?: ClassNameValue; } |
插槽
| 插槽 | 类型 |
|---|---|
default | { item: T; index: number; } |
事件
| 事件 | 类型 |
|---|---|
select | [selectedIndex: number] |
可访问属性
您可以使用useTemplateRef.
<script setup lang="ts">
const carousel = useTemplateRef('carousel')
</script>
<template>
<UCarousel ref="carousel" />
</template>
这将使您能够访问以下内容
| 名称 | 类型 |
|---|---|
emblaRef | Ref<HTMLElement | null> |
emblaApi | Ref<EmblaCarouselType | null> |
主题
export default defineAppConfig({
ui: {
carousel: {
slots: {
root: 'relative focus:outline-none',
viewport: 'overflow-hidden',
container: 'flex items-start',
item: 'min-w-0 shrink-0 basis-full',
controls: '',
arrows: '',
prev: 'absolute rounded-full',
next: 'absolute rounded-full',
dots: 'absolute inset-x-0 -bottom-7 flex flex-wrap items-center justify-center gap-3',
dot: [
'cursor-pointer size-3 bg-accented rounded-full focus:outline-none focus-visible:ring-2 focus-visible:ring-primary',
'transition'
]
},
variants: {
orientation: {
vertical: {
container: 'flex-col -mt-4',
item: 'pt-4',
prev: 'top-4 sm:-top-12 left-1/2 -translate-x-1/2 rotate-90 rtl:-rotate-90',
next: 'bottom-4 sm:-bottom-12 left-1/2 -translate-x-1/2 rotate-90 rtl:-rotate-90'
},
horizontal: {
container: 'flex-row -ms-4',
item: 'ps-4',
prev: 'start-4 sm:-start-12 top-1/2 -translate-y-1/2',
next: 'end-4 sm:-end-12 top-1/2 -translate-y-1/2'
}
},
active: {
true: {
dot: 'data-[state=active]:bg-inverted'
}
}
}
}
}
})
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
carousel: {
slots: {
root: 'relative focus:outline-none',
viewport: 'overflow-hidden',
container: 'flex items-start',
item: 'min-w-0 shrink-0 basis-full',
controls: '',
arrows: '',
prev: 'absolute rounded-full',
next: 'absolute rounded-full',
dots: 'absolute inset-x-0 -bottom-7 flex flex-wrap items-center justify-center gap-3',
dot: [
'cursor-pointer size-3 bg-accented rounded-full focus:outline-none focus-visible:ring-2 focus-visible:ring-primary',
'transition'
]
},
variants: {
orientation: {
vertical: {
container: 'flex-col -mt-4',
item: 'pt-4',
prev: 'top-4 sm:-top-12 left-1/2 -translate-x-1/2 rotate-90 rtl:-rotate-90',
next: 'bottom-4 sm:-bottom-12 left-1/2 -translate-x-1/2 rotate-90 rtl:-rotate-90'
},
horizontal: {
container: 'flex-row -ms-4',
item: 'ps-4',
prev: 'start-4 sm:-start-12 top-1/2 -translate-y-1/2',
next: 'end-4 sm:-end-12 top-1/2 -translate-y-1/2'
}
},
active: {
true: {
dot: 'data-[state=active]:bg-inverted'
}
}
}
}
}
})
]
})