🌐 Nodejs.cn

使用 Embla 构建的具有运动和滑动功能的轮播。

1
2
3
4
5
<script setup lang="ts">
import { Card, CardContent } from '@/components/ui/card'
import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselNext,
  CarouselPrevious,
} from '@/components/ui/carousel'
</script>

<template>
  <Carousel class="w-full max-w-xs">
    <CarouselContent>
      <CarouselItem v-for="i in 5" :key="i">
        <div class="p-1">
          <Card>
            <CardContent class="flex aspect-square items-center justify-center p-6">
              <span class="text-4xl font-semibold">{{ i }}</span>
            </CardContent>
          </Card>
        </div>
      </CarouselItem>
    </CarouselContent>
    <CarouselPrevious />
    <CarouselNext />
  </Carousel>
</template>

安装

🌐 Installation

pnpm dlx shadcn-vue@latest add carousel

用法

🌐 Usage

<script setup lang="ts">
import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselNext,
  CarouselPrevious,
} from '@/components/ui/carousel'
</script>

<template>
  <Carousel>
    <CarouselContent>
      <CarouselItem>...</CarouselItem>
      <CarouselItem>...</CarouselItem>
      <CarouselItem>...</CarouselItem>
    </CarouselContent>
    <CarouselPrevious />
    <CarouselNext />
  </Carousel>
</template>

示例

🌐 Examples

大小

🌐 Sizes

要设置项目的大小,你可以在 <CarouselItem /> 上使用 basis 工具类。

🌐 To set the size of the items, you can use the basis utility class on the <CarouselItem />.

1
2
3
4
5
<script setup lang="ts">
import { Card, CardContent } from '@/components/ui/card'
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/components/ui/carousel'
</script>

<template>
  <Carousel
    class="relative w-full max-w-xs"
    :opts="{
      align: 'start',
    }"
  >
    <CarouselContent>
      <CarouselItem v-for="(_, index) in 5" :key="index" class="md:basis-1/2 lg:basis-1/3">
        <div class="p-1">
          <Card>
            <CardContent class="flex aspect-square items-center justify-center p-6">
              <span class="text-3xl font-semibold">{{ index + 1 }}</span>
            </CardContent>
          </Card>
        </div>
      </CarouselItem>
    </CarouselContent>
    <CarouselPrevious />
    <CarouselNext />
  </Carousel>
</template>
// 33% of the carousel width.
<template>
  <Carousel>
    <CarouselContent>
      <CarouselItem class="basis-1/3">
        ...
      </CarouselItem>
      <CarouselItem class="basis-1/3">
        ...
      </CarouselItem>
      <CarouselItem class="basis-1/3">
        ...
      </CarouselItem>
    </CarouselContent>
  </Carousel>
</template>
// 50% on small screens and 33% on larger screens.
<template>
  <Carousel>
    <CarouselContent>
      <CarouselItem class="md:basis-1/2 lg:basis-1/3">
        ...
      </CarouselItem>
      <CarouselItem class="md:basis-1/2 lg:basis-1/3">
        ...
      </CarouselItem>
      <CarouselItem class="md:basis-1/2 lg:basis-1/3">
        ...
      </CarouselItem>
    </CarouselContent>
  </Carousel>
</template>

间距

🌐 Spacing

要设置项目之间的间距,我们在 <CarouselItem /> 上使用 pl-[VALUE] 工具,并在 <CarouselContent /> 上使用负 -ml-[VALUE]

🌐 To set the spacing between the items, we use a pl-[VALUE] utility on the <CarouselItem /> and a negative -ml-[VALUE] on the <CarouselContent />.

1
2
3
4
5
<script setup lang="ts">
import { Card, CardContent } from '@/components/ui/card'
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/components/ui/carousel'
</script>

<template>
  <Carousel
    class="w-full max-w-sm"
    :opts="{
      align: 'start',
    }"
  >
    <CarouselContent class="-ml-1">
      <CarouselItem v-for="(_, index) in 5" :key="index" class="pl-1 md:basis-1/2 lg:basis-1/3">
        <div class="p-1">
          <Card>
            <CardContent class="flex aspect-square items-center justify-center p-6">
              <span class="text-2xl font-semibold">{{ index + 1 }}</span>
            </CardContent>
          </Card>
        </div>
      </CarouselItem>
    </CarouselContent>
    <CarouselPrevious />
    <CarouselNext />
  </Carousel>
</template>
<template>
  <Carousel>
    <CarouselContent class="-ml-4">
      <CarouselItem class="pl-4">
        ...
      </CarouselItem>
      <CarouselItem class="pl-4">
        ...
      </CarouselItem>
      <CarouselItem class="pl-4">
        ...
      </CarouselItem>
    </CarouselContent>
  </Carousel>
</template>
<template>
  <Carousel>
    <CarouselContent class="-ml-2 md:-ml-4">
      <CarouselItem class="pl-2 md:pl-4">
        ...
      </CarouselItem>
      <CarouselItem class="pl-2 md:pl-4">
        ...
      </CarouselItem>
      <CarouselItem class="pl-2 md:pl-4">
        ...
      </CarouselItem>
    </CarouselContent>
  </Carousel>
</template>

方向

🌐 Orientation

使用 orientation 属性来设置轮播的方向。

🌐 Use the orientation prop to set the orientation of the carousel.

1
2
3
4
5
<script setup lang="ts">
import { Card, CardContent } from '@/components/ui/card'
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/components/ui/carousel'
</script>

<template>
  <Carousel
    orientation="vertical"
    class="relative w-full max-w-xs"
    :opts="{
      align: 'start',
    }"
  >
    <CarouselContent class="-mt-1 h-[200px]">
      <CarouselItem v-for="(_, index) in 5" :key="index" class="p-1 md:basis-1/2">
        <div class="p-1">
          <Card>
            <CardContent class="flex items-center justify-center p-6">
              <span class="text-3xl font-semibold">{{ index + 1 }}</span>
            </CardContent>
          </Card>
        </div>
      </CarouselItem>
    </CarouselContent>
    <CarouselPrevious />
    <CarouselNext />
  </Carousel>
</template>
<Carousel orientation="vertical | horizontal">
  ...
</Carousel>

选项

🌐 Options

你可以使用 opts 属性向轮播传递选项。有关更多信息,请参见 Embla Carousel 文档

🌐 You can pass options to the carousel using the opts prop. See the Embla Carousel docs for more information.

<template>
  <Carousel
    :opts="{
      align: 'start',
      loop: true,
    }"
  >
    <CarouselContent>
      <CarouselItem>...</CarouselItem>
      <CarouselItem>...</CarouselItem>
      <CarouselItem>...</CarouselItem>
    </CarouselContent>
  </Carousel>
</template>

应用编程接口

🌐 API

方法 1

🌐 Method 1

<Carousel /> 组件上使用 @init-api emit 方法来设置 API 的实例。

🌐 Use the @init-api emit method on <Carousel /> component to set the instance of the API.

1
2
3
4
5
Slide 0 of 0
<script setup lang="ts">
import type { CarouselApi } from '@/components/ui/carousel'
import { watchOnce } from '@vueuse/core'
import { ref } from 'vue'
import { Card, CardContent } from '@/components/ui/card'
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/components/ui/carousel'

const api = ref<CarouselApi>()
const totalCount = ref(0)
const current = ref(0)

function setApi(val: CarouselApi) {
  api.value = val
}

watchOnce(api, (api) => {
  if (!api)
    return

  totalCount.value = api.scrollSnapList().length
  current.value = api.selectedScrollSnap() + 1

  api.on('select', () => {
    current.value = api.selectedScrollSnap() + 1
  })
})
</script>

<template>
  <div class="w-full sm:w-auto">
    <Carousel class="relative w-full max-w-xs" @init-api="setApi">
      <CarouselContent>
        <CarouselItem v-for="(_, index) in 5" :key="index">
          <div class="p-1">
            <Card>
              <CardContent class="flex aspect-square items-center justify-center p-6">
                <span class="text-4xl font-semibold">{{ index + 1 }}</span>
              </CardContent>
            </Card>
          </div>
        </CarouselItem>
      </CarouselContent>
      <CarouselPrevious />
      <CarouselNext />
    </Carousel>

    <div class="py-2 text-center text-sm text-muted-foreground">
      Slide {{ current }} of {{ totalCount }}
    </div>
  </div>
</template>

方法二

🌐 Method 2

你可以通过在 <Carousel /> 组件上设置模板引用来访问它。

🌐 You can access it through setting a template ref on the <Carousel /> component.

<script setup lang="ts">
const carouselContainerRef = ref<InstanceType<typeof Carousel> | null>(null)

function accessApi() {
  carouselContainerRef.value?.carouselApi.on('select', () => {})
}
</script>

<template>
  <Carousel ref="carouselContainerRef">
    ...
  </Carousel>
</template>

事件

🌐 Events

你可以使用 API 来监听事件。要获取 API 实例,请在 <Carousel /> 组件上使用 @init-api emit 方法

🌐 You can listen to events using the API. To get the API instance use the @init-api emit method on the <Carousel /> component

<script setup lang="ts">
import { nextTick, ref, watch } from 'vue'
import { useCarousel } from '@/components/ui/carousel'

const api = ref<CarouselApi>()

function setApi(val: CarouselApi) {
  api.value = val
}

const stop = watch(api, (api) => {
  if (!api)
    return

  // Watch only once or use watchOnce() in @vueuse/core
  nextTick(() => stop())

  api.on('select', () => {
    // Do something on select.
  })
})
</script>

<template>
  <Carousel @init-api="setApi">
    ...
  </Carousel>
</template>

有关使用事件的更多信息,请参阅 Embla Carousel 文档

🌐 See the Embla Carousel docs for more information on using events.

插槽属性

🌐 Slot Props

你可以在 <Carousel v-slot="slotProps" /> 组件中使用 v-slot 指令获取响应式插槽属性,如 carouselRef, canScrollNext..Prev, scrollNext..Prev,以扩展功能。

🌐 You can get the reactive slot props like carouselRef, canScrollNext..Prev, scrollNext..Prev using the v-slot directive in the <Carousel v-slot="slotProps" /> component to extend the functionality.

<template>
  <Carousel v-slot="{ canScrollNext, canScrollPrev }">
    ...
    <CarouselPrevious v-if="canScrollPrev" />
    <CarouselNext v-if="canScrollNext" />
  </Carousel>
</template>

插件

🌐 Plugins

你可以使用 plugins 属性向轮播添加插件。

🌐 You can use the plugins prop to add plugins to the carousel.

pnpm add embla-carousel-autoplay
<script setup lang="ts">
import Autoplay from 'embla-carousel-autoplay'
</script>

<template>
  <Carousel
    class="w-full max-w-xs"
    :plugins="[Autoplay({
      delay: 2000,
    })]"
  >
    ...
  </Carousel>
</template>
1
2
3
4
5
<script setup lang="ts">
import Autoplay from 'embla-carousel-autoplay'
import { Card, CardContent } from '@/components/ui/card'
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/components/ui/carousel'

const plugin = Autoplay({
  delay: 2000,
  stopOnMouseEnter: true,
  stopOnInteraction: false,
})
</script>

<template>
  <Carousel
    class="relative w-full max-w-xs"
    :plugins="[plugin]"
    @mouseenter="plugin.stop"
    @mouseleave="[plugin.reset(), plugin.play(), console.log('Running')];"
  >
    <CarouselContent>
      <CarouselItem v-for="(_, index) in 5" :key="index">
        <div class="p-1">
          <Card>
            <CardContent class="flex aspect-square items-center justify-center p-6">
              <span class="text-4xl font-semibold">{{ index + 1 }}</span>
            </CardContent>
          </Card>
        </div>
      </CarouselItem>
    </CarouselContent>
    <CarouselPrevious />
    <CarouselNext />
  </Carousel>
</template>

有关使用插件的更多信息,请参阅 Embla Carousel 文档

🌐 See the Embla Carousel docs for more information on using plugins.