组件
- 手风琴 (Accordion)
- 警告 (Alert)
- 警告对话框 (Alert Dialog)
- 宽高比 (Aspect Ratio)
- 头像 (Avatar)
- 徽章 (Badge)
- 面包屑 (Breadcrumb)
- 按钮 (Button)
- 按钮组 (Button Group)
- 日历 (Calendar)
- 卡片 (Card)
- 轮播图 (Carousel)
- 图表 (Chart)
- 复选框 (Checkbox)
- 折叠面板 (Collapsible)
- 组合框 (Combobox)
- 命令面板 (Command)
- 上下文菜单 (Context Menu)
- 数据表格 (Data Table)
- 日期选择器 (Date Picker)
- 对话框 (Dialog)
- 抽屉 (Drawer)
- 下拉菜单 (Dropdown Menu)
- 空状态 (Empty)
- 字段 (Field)
- 表单 (Form)
- 悬停卡片 (Hover Card)
- 输入框 (Input)
- 输入组 (Input Group)
- 验证码输入 (Input OTP)
- 项 (Item)
- 键盘按键 (Kbd)
- 标签 (Label)
- 菜单栏 (Menubar)
- 原生选择器 (Native Select)
- 导航菜单 (Navigation Menu)
- 数字输入框 (Number Field)
- 分页 (Pagination)
- 引脚输入 (Pin Input)
- 气泡卡片 (Popover)
- 进度条 (Progress)
- 单选框组 (Radio Group)
- 范围日历 (Range Calendar)
- 可调整大小 (Resizable)
- 滚动区域 (Scroll Area)
- 选择器 (Select)
- 分隔线 (Separator)
- 侧边栏抽屉 (Sheet)
- 侧边栏 (Sidebar)
- 骨架屏 (Skeleton)
- 滑块 (Slider)
- 轻量提示 (Sonner)
- 加载动画 (Spinner)
- 步骤条 (Stepper)
- 开关 (Switch)
- 表格 (Table)
- 标签页 (Tabs)
- 标签输入 (Tags Input)
- 文本域 (Textarea)
- 吐司提示 (Toast)
- 切换按钮 (Toggle)
- 切换按钮组 (Toggle Group)
- 工具提示 (Tooltip)
- 排版 (Typography)
开始使用
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>安装
pnpm dlx shadcn-vue@latest add carousel
使用方法
<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>示例
尺寸
若要设置项目的尺寸,可以在 <CarouselItem /> 上使用 basis 工具类。
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>间距
要设置项目之间的间距,我们在 <CarouselItem /> 上使用 pl-[VALUE] 工具类,并在 <CarouselContent /> 上使用负值 -ml-[VALUE]。
原因:我尝试在 <CarouselContent /> 上使用 gap 属性或 grid 布局,但需要大量的数学计算和精力才能确保间距正确。我发现使用 pl-[VALUE] 和 -ml-[VALUE] 工具类要容易得多。
如果需要,你始终可以在自己的项目中进行调整。
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 属性来设置轮播的方向。
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>选项
你可以通过 opts 属性将选项传递给轮播组件。更多信息请参阅 Embla Carousel 文档。
<template>
<Carousel
:opts="{
align: 'start',
loop: true,
}"
>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
</template>API
方法 1
在 <Carousel /> 组件上使用 @init-api 发射方法来设置 API 实例。
1
2
3
4
5
第 0 张 / 共 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>方法 2
你可以通过在 <Carousel /> 组件上设置模板引用 (template ref) 来访问它。
<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>事件
你可以使用 API 监听事件。要获取 API 实例,请在 <Carousel /> 组件上使用 @init-api 发射方法。
<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 文档。
插槽属性 (Slot Props)
你可以使用 v-slot 指令在 <Carousel v-slot="slotProps" /> 组件中获取响应式的插槽属性,如 carouselRef, canScrollNext..Prev, scrollNext..Prev,以扩展功能。
<template>
<Carousel v-slot="{ canScrollNext, canScrollPrev }">
...
<CarouselPrevious v-if="canScrollPrev" />
<CarouselNext v-if="canScrollNext" />
</Carousel>
</template>插件
你可以使用 plugins 属性为轮播添加插件。
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 文档。