Carousel 轮播图
由 Embla Carousel 驱动的触摸友好型轮播组件,具备流畅的物理滑动惯性,适用于图片画廊、产品展示、功能介绍等场景。
预览
🔥 新粗野主义
大胆边框 + 硬朗阴影
💡 简洁至上
去掉多余的装饰
⚡ 高对比度
清晰的视觉层次感
程序化控制
1 / 3
🔥 新粗野主义
2 / 3
💡 简洁至上
3 / 3
⚡ 高对比度
提示:本组件尊重系统的「减少动态效果」设置。启用后将停止自动播放并禁用幻灯片切换的过渡动画。
安装
pnpm dlx brutx-vue@latest add carousel用法
<script setup>
import { Carousel, CarouselItem } from 'brutx-ui-vue/carousel'
</script>
<template>
<Carousel :loop="true" :autoplay="true" :autoplay-delay="3000" size="md">
<CarouselItem>
<div class="w-full h-full flex items-center justify-center bg-brutal-primary border-3 border-brutal">
幻灯片 1
</div>
</CarouselItem>
<CarouselItem>
<div class="w-full h-full flex items-center justify-center bg-brutal-secondary border-3 border-brutal">
幻灯片 2
</div>
</CarouselItem>
</Carousel>
</template>尺寸
| 尺寸 | 说明 |
|---|---|
sm | 小尺寸 |
md | 中等尺寸 |
lg | 大尺寸 |
full | 全屏高度 |
default | 默认尺寸 |
子组件
| 组件 | 说明 |
|---|---|
Carousel | 轮播容器,管理滚动逻辑与导航控制 |
CarouselItem | 单张幻灯片容器 |
组合式函数
Carousel 组件内部逻辑已抽取为独立的 useCarousel 组合式函数,可单独使用以构建完全自定义的轮播 UI。它基于 embla-carousel-vue 封装,内置自动播放、循环控制、选中索引追踪,并自动遵守 prefers-reduced-motion 系统偏好(启用减少动效时会停止自动播放并禁用过渡动画)。
import { useCarousel } from 'brutx-ui-vue/useCarousel'
import type { UseCarouselOptions } from 'brutx-ui-vue/useCarousel'
const options: UseCarouselOptions = {
loop: true,
autoplay: true,
autoplayDelay: 3000,
}
const {
emblaRef, // 绑定到轮播容器的 ref
selectedIndex, // 当前选中幻灯片索引
scrollSnaps, // 所有滚动停靠点
canScrollPrev, // 是否可向前滚动
canScrollNext, // 是否可向后滚动
scrollPrev, // 滚动到上一张
scrollNext, // 滚动到下一张
scrollTo, // 滚动到指定索引
startAutoplay, // 启动自动播放
stopAutoplay, // 停止自动播放
} = useCarousel(options)选项
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
loop | MaybeRefOrGetter<boolean | undefined> | false | 是否开启首尾循环滚动 |
autoplay | MaybeRefOrGetter<boolean | undefined> | false | 是否自动播放 |
autoplayDelay | MaybeRefOrGetter<number | undefined> | 3000 | 自动播放间隔(毫秒) |
返回值
| 属性 | 类型 | 说明 |
|---|---|---|
emblaRef | Ref<HTMLElement | undefined> | 绑定到轮播容器的 ref(传给 <template> 中的容器元素) |
selectedIndex | Ref<number> | 当前选中幻灯片索引 |
scrollSnaps | Ref<number[]> | 所有可停靠的滚动位置 |
canScrollPrev | ComputedRef<boolean> | 是否可向前滚动(非循环模式下到达首张时为 false) |
canScrollNext | ComputedRef<boolean> | 是否可向后滚动(非循环模式下到达末张时为 false) |
scrollPrev() | () => void | 滚动到上一张 |
scrollNext() | () => void | 滚动到下一张 |
scrollTo(index) | (index: number) => void | 滚动到指定索引 |
startAutoplay() | () => void | 启动自动播放(受 autoplay 选项与减少动效偏好控制) |
stopAutoplay() | () => void | 停止自动播放 |
提示:
useCarousel会在内部onMounted注册 Embla 事件、onUnmounted清理监听与计时器,必须在setup顶层调用。
程序化控制
Carousel 通过 defineExpose 暴露了一组方法与状态,可通过组件 ref 在父组件中主动控制轮播的滚动与读取当前状态,无需自行接管 Embla 实例。
<script setup>
import { ref } from 'vue'
import { Carousel, CarouselItem } from 'brutx-ui-vue/carousel'
const carouselRef = ref()
</script>
<template>
<Carousel ref="carouselRef" :loop="true">
<CarouselItem v-for="i in 5" :key="i">
<div class="w-full h-full flex items-center justify-center">幻灯片 {{ i }}</div>
</CarouselItem>
</Carousel>
<div class="flex gap-2 mt-4">
<button @click="carouselRef?.scrollPrev()">上一张</button>
<button @click="carouselRef?.scrollNext()">下一张</button>
<button @click="carouselRef?.scrollTo(0)">回到首张</button>
</div>
</template>API 参考
Carousel
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
loop | boolean | undefined | false | 启用首尾循环滚动;启用后上一张和下一张始终可滚动。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/carousel/types.ts | |||
autoplay | boolean | undefined | false | 启用轮播自动播放;减少动态效果偏好生效时自动播放会停止。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/carousel/types.ts | |||
autoplayDelay | number | undefined | 3000 | 设置自动播放切换幻灯片的间隔,单位为毫秒。 |
详情声明类型number | undefined 默认值详情
来源packages/ui/src/components/carousel/types.ts | |||
showArrows | boolean | undefined | true | 控制是否显示上一张和下一张导航按钮。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/carousel/types.ts | |||
showDots | boolean | undefined | true | 控制是否显示底部圆点导航;显示缩略图时圆点导航会隐藏。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/carousel/types.ts | |||
size | "default" | "lg" | "sm" | "md" | "full" | undefined | "default" | 设置轮播视口的高度预设。 |
详情声明类型"default" | "lg" | "sm" | "md" | "full" | undefined 字面量
默认值详情
来源packages/ui/src/components/carousel/types.ts | |||
thumbnails | CarouselThumbnails | undefined | { "gap": 8, "highlightCurrent": true, "position": "bottom", "show": false, "size": "sm" }按实例调用工厂函数 | 配置缩略图导航的显示、位置、尺寸、间距和当前项高亮。 |
详情声明类型CarouselThumbnails | undefined 关联类型 CarouselThumbnails 类型定义 — CarouselThumbnailsexport interface CarouselThumbnails {
show?: boolean
position?: 'bottom' | 'left' | 'right'
size?: 'sm' | 'md' | 'lg'
gap?: number
highlightCurrent?: boolean
}默认值详情
来源packages/ui/src/components/carousel/types.ts | |||
autoplayIndicator | AutoplayIndicator | undefined | undefined | 配置自动播放指示器的类型、位置和悬停暂停行为。 |
详情声明类型AutoplayIndicator | undefined 关联类型 AutoplayIndicator 类型定义 — AutoplayIndicatorexport interface AutoplayIndicator {
type: 'progress' | 'dots' | 'fraction'
position?: 'top' | 'bottom'
pauseOnHover?: boolean
}默认值详情
来源packages/ui/src/components/carousel/types.ts | |||
parallax | ParallaxEffect | undefined | undefined | 配置幻灯片视差效果及其缩放、透明度和动画时长。 |
详情声明类型ParallaxEffect | undefined 关联类型 ParallaxEffect 类型定义 — ParallaxEffectexport interface ParallaxEffect {
enabled?: boolean
scale?: number
opacity?: boolean
duration?: number
easing?: string
}默认值详情
来源packages/ui/src/components/carousel/types.ts | |||
class | string | undefined | undefined | 追加到轮播根元素的 CSS 类。 |
详情声明类型string | undefined 默认值详情
来源packages/ui/src/components/carousel/types.ts | |||
| 名称 | 签名或类型 | 说明 |
|---|---|---|
#default | {} | 放置 CarouselItem 幻灯片组件。 |
详情声明类型{}来源packages/ui/src/components/carousel/Carousel.vue | ||
#thumbnail | { index: number; scrollTo: (index: number) => void; } | 自定义缩略图内容;作用域提供当前缩略图 index 和跳转到指定项的 scrollTo 函数。 |
详情声明类型{ index: number; scrollTo: (index: number) => void; }来源packages/ui/src/components/carousel/Carousel.vue | ||
| 名称 | 签名或类型 | 说明 |
|---|---|---|
scrollPrev | () => void | 滚动到上一张幻灯片;循环模式下可从第一张回到最后一张。 |
详情声明类型() => void 来源packages/ui/src/components/carousel/Carousel.vue | ||
scrollNext | () => void | 滚动到下一张幻灯片;循环模式下可从最后一张回到第一张。 |
详情声明类型() => void 来源packages/ui/src/components/carousel/Carousel.vue | ||
scrollTo | (index: number) => void | 滚动到指定的从零开始的幻灯片索引。 |
详情声明类型(index: number) => void 来源packages/ui/src/components/carousel/Carousel.vue | ||
selectedIndex | number | 当前选中幻灯片的从零开始索引,只读响应式状态。 |
详情声明类型number 来源packages/ui/src/components/carousel/Carousel.vue | ||
canScrollPrev | boolean | 指示当前是否可以向前滚动;循环模式下始终为 true。 |
详情声明类型boolean 字面量
来源packages/ui/src/components/carousel/Carousel.vue | ||
canScrollNext | boolean | 指示当前是否可以向后滚动;循环模式下始终为 true。 |
详情声明类型boolean 字面量
来源packages/ui/src/components/carousel/Carousel.vue | ||
startAutoplay | () => void | 开始自动播放;减少动态效果偏好仍会阻止播放。 |
详情声明类型() => void 来源packages/ui/src/components/carousel/Carousel.vue | ||
stopAutoplay | () => void | 停止自动播放。 |
详情声明类型() => void 来源packages/ui/src/components/carousel/Carousel.vue | ||
CarouselItem
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
class | string | undefined | undefined | 追加到单张幻灯片容器的 CSS 类。 |
详情声明类型string | undefined 默认值详情
来源packages/ui/src/components/carousel/CarouselItem.vue | |||
ariaHidden | boolean | undefined | undefined | 将当前幻灯片及其后代标记为对辅助技术隐藏;视口外幻灯片应设为 true。 |
详情声明类型boolean | undefined 字面量
默认值详情
来源packages/ui/src/components/carousel/CarouselItem.vue | |||
| 名称 | 签名或类型 | 说明 |
|---|---|---|
#default | {} | 单张幻灯片中展示的自定义内容。 |
详情声明类型{}来源packages/ui/src/components/carousel/CarouselItem.vue | ||
Carousel 增强能力
Carousel 已内置缩略图导航、自动播放指示器(进度条/圆点/分数)与视差动画效果,适用于图片画廊、产品展示等需要更丰富交互的场景。
用法
<script setup>
import { Carousel, CarouselItem } from 'brutx-ui-vue/carousel'
</script>
<template>
<Carousel
:loop="true"
:autoplay="true"
:autoplay-delay="3000"
size="md"
:thumbnails="{ show: true, position: 'bottom', size: 'sm', gap: 8, highlightCurrent: true }"
:autoplay-indicator="{ type: 'progress', position: 'top', pauseOnHover: true }"
:parallax="{ enabled: true, scale: 1.05, opacity: true, duration: 400 }"
>
<CarouselItem v-for="slide in slides" :key="slide.label">
<div class="w-full h-full flex items-center justify-center">{{ slide.label }}</div>
</CarouselItem>
</Carousel>
</template>CarouselThumbnails
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
show | boolean | false | 是否显示缩略图 |
position | 'bottom' | 'left' | 'right' | 'bottom' | 缩略图位置 |
size | 'sm' | 'md' | 'lg' | 'sm' | 缩略图尺寸 |
gap | number | 8 | 缩略图间距(像素) |
highlightCurrent | boolean | true | 是否高亮当前缩略图 |
AutoplayIndicator
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
type | 'progress' | 'dots' | 'fraction' | —(必填) | 指示器类型:进度条 / 圆点 / 分数 |
position | 'top' | 'bottom' | — | 指示器位置 |
pauseOnHover | boolean | — | 鼠标悬停时暂停自动播放 |
ParallaxEffect
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enabled | boolean | false | 是否启用视差动画 |
scale | number | 1.1 | 幻灯片缩放比例 |
opacity | boolean | false | 是否启用透明度过渡 |
duration | number | 300 | 动画时长(毫秒) |
easing | string | 'ease-out' | CSS 缓动函数 |
可访问性
- ARIA 属性:左右箭头按钮均带有
aria-label;导航圆点按钮均带有aria-label - 焦点管理:键盘焦点管理由 Embla 内置支持
- 动效降级:组件尊重
prefers-reduced-motion系统设置。当用户启用"减少动态效果"时(由内部useCarousel组合式函数通过useReducedMotion监听):- 停止自动播放:
autoplay不再触发,已有的定时器会被清除 - 禁用过渡动画:通过
emblaApi.reInit({ duration: 0 })让幻灯片切换不再带有滑动惯性,直接跳转到位 - 实时响应:偏好变化时立即生效,无需重新挂载组件;恢复默认设置后会还原过渡时长并在
autoplay开启时恢复播放
- 停止自动播放:
键盘焦点进入轮播及其内部控件时会暂停自动播放;焦点在轮播内切换时保持暂停,焦点离开后仅在自动播放此前仍运行、且未被手动停止时恢复。鼠标悬停是否暂停由 autoplayIndicator.pauseOnHover 控制;未配置自动播放指示器时默认暂停。悬停暂停已启用时,鼠标或键盘焦点任一仍在轮播区域都会让自动播放保持暂停。
增强能力额外说明
- 缩略图按钮:每个缩略图为
<button type="button">,带有aria-label(通过t('carousel.goToSlide', { index })国际化);当前缩略图通过视觉高亮标识 - 导航去重:当缩略图显示时,默认底部圆点导航自动隐藏(
showDots与thumbnails.show互斥),避免重复导航 - 自动播放指示器:进度条 / 分数 / 圆点均为装饰性视觉元素(
<div>),不提供交互,不抢夺焦点 - 悬停暂停:
autoplayIndicator.pauseOnHover启用时,鼠标进入轮播区域会暂停自动播放,离开后恢复 - 视差动画:通过 CSS 变量驱动,继承
useCarousel的prefers-reduced-motion处理,启用减少动效时视差缩放与透明度过渡同样被禁用
常见问题
Q: 开启 loop 后为什么箭头按钮状态没有变化?
A: 当 loop 设为 true 时,canScrollPrev 和 canScrollNext 始终为 true,因为循环模式下总是可以继续滚动。这是正常行为,箭头按钮会始终保持可用状态。
Q: 自动播放在某些设备上不生效,是什么原因?
A: 组件会自动遵守系统的"减少动态效果"偏好设置。如果用户在系统设置中启用了"减少动态效果",自动播放将被禁用。此外,在页面不可见时自动播放也会暂停,切换回页面后会恢复。
Q: 如何在轮播切换时执行自定义逻辑?
A: 通过 ref 获取组件实例后,可以监听 selectedIndex 的变化。也可以使用 useCarousel 组合式函数自行构建轮播 UI,它暴露了完整的 Embla 事件接口,可以注册 select、scroll 等事件回调。