Carousel
基础布局基于 Bootstrap 5 的 Carousel 轮播组件,支持指示器、控制按钮、标题、自动播放(悬停暂停)、单张间隔、键盘与触摸切换、受控模式;滑动与淡入淡出过渡为自定义实现,状态由 useReducer 统一驱动,并通过双 requestAnimationFrame 保证首次挂载动画生效,同时尊重减少动态效果偏好
Component Demo
Basic usage and examples of the Carousel component
仅幻灯片
带控制按钮
带指示器
带标题
交叉淡入淡出
第一张幻灯片
第二张幻灯片
第三张幻灯片
自动播放
ride="carousel":挂载后立即播放,悬停或聚焦时暂停
ride:首次手动切换后开始播放
单独设置切换间隔
禁用触摸滑动
深色变体
受控用法
当前索引:
0过渡时长与减少动态效果
duration={1200} 搭配自定义缓动变量
slide={false}:直接切换,无过渡
系统开启“减少动态效果”(prefers-reduced-motion: reduce)时,过渡时长会自动按 0 处理并直接切换。
过渡事件
- 切换幻灯片后在此查看事件顺序
API Documentation
Complete API reference for the Carousel component
Props
Carousel
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
activeIndex | number | - | 受控的当前幻灯片索引,提供时由外部驱动,需配合 `onSelect` 更新 |
defaultActiveIndex | number | 0 | 非受控模式下的初始幻灯片索引 |
duration | number | 600 | 过渡动画时长(毫秒),会写入 `--rbs-carousel-duration`;系统开启减少动态效果或 `slide` 为 `false` 时按 `0` 处理 |
fade | boolean | false | 使用交叉淡入淡出过渡替代默认的横向滑动过渡(自定义实现,不使用 `carousel-fade`) |
slide | boolean | true | 是否启用过渡动画,为 `false` 时直接切换幻灯片 |
interval | null | number | 5000 | 自动播放的切换间隔(毫秒),为 `null` 或小于等于 `0` 时不自动切换;可被 `CarouselItem` 的 `interval` 覆盖 |
ride | CarouselRide | false | 自动播放策略:`"carousel"` 挂载后立即播放,`true` 首次交互后开始播放,`false` 不自动播放 |
pause | CarouselPause | 'hover' | 为 `"hover"` 时鼠标悬停或键盘聚焦暂停自动播放,移出后恢复;为 `false` 时不暂停。页面切到后台时始终暂停 |
wrap | boolean | true | 是否循环播放,为 `false` 时到达首尾后停止,控制按钮会自动禁用 |
keyboard | boolean | true | 是否响应键盘左右方向键(焦点位于轮播内部时生效,输入类元素中不触发) |
touch | boolean | true | 是否支持触摸、触控笔的左右滑动切换(滑动阈值 40px,纵向滑动不触发) |
onSelect | (index: number, direction: CarouselDirection) => void | - | 请求切换回调,由控制按钮、指示器、键盘、滑动或自动播放触发;受控模式下由使用者更新 `activeIndex` |
onSlide | (index: number, direction: CarouselDirection) => void | - | 过渡开始时触发,对应 Bootstrap 的 `slide.bs.carousel` 事件 |
onSlid | (index: number, direction: CarouselDirection) => void | - | 过渡结束、当前索引更新后触发,对应 Bootstrap 的 `slid.bs.carousel` 事件 |
role | AriaRole | 'region' | 无障碍角色,建议同时提供 `aria-label` 说明轮播用途 |
aria-roledescription | string | 'carousel' | 无障碍角色描述,读屏软件会将该区域朗读为“轮播”而非普通区域 |
children | ReactNode | - | 轮播内容,通常为 `CarouselIndicators`、`CarouselInner` 与 `CarouselControl` |
className | string | - | 自定义类名 |
style | CarouselCssProperties | - | 内联样式,支持覆盖 `--rbs-carousel-*` 自定义变量(如缓动函数、滑动距离) |
...rest | HTMLAttributes | - | 透传原生 div 元素的所有属性(如 `id`、`data-bs-theme` 等) |
CarouselInner
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
children | ReactNode | - | 幻灯片列表,每个子节点会被自动注入索引,因此 `CarouselItem` 无需手动指定 `index` |
aria-live | 'assertive' | 'off' | 'polite' | 'off' | 'polite' | 无障碍实时区域属性,自动播放时为 `"off"`,未自动播放时为 `"polite"` |
className | string | - | 自定义类名 |
...rest | HTMLAttributes | - | 透传原生 div 元素的所有属性 |
CarouselItem
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
interval | number | - | 该幻灯片单独的自动切换间隔(毫秒),优先于 `Carousel` 的 `interval`,仅在该幻灯片为当前项时生效 |
index | number | - | 手动指定索引,默认由 `CarouselInner` 按子节点顺序注入 |
children | ReactNode | - | 幻灯片内容,可为图片、纯色区块或任意自定义内容 |
role | AriaRole | 'group' | 无障碍角色,配合 `aria-roledescription="slide"` 使用 |
aria-label | string | '{index} / {count}' | 无障碍标签,默认为当前序号与总数,可替换为更具体的描述 |
className | string | - | 自定义类名 |
...rest | HTMLAttributes | - | 透传原生 div 元素的所有属性(`onTransitionEnd` 会在内部逻辑之后调用) |
CarouselIndicators
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
children | ReactNode | - | 自定义指示器内容,未提供时按幻灯片数量自动生成 `CarouselIndicator` |
labels | string[] | - | 自动生成指示器时使用的无障碍标签数组,未提供的项回退为 `Slide N` |
className | string | - | 自定义类名 |
...rest | HTMLAttributes | - | 透传原生 div 元素的所有属性 |
CarouselIndicator
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
index | number | - | 对应的幻灯片索引,点击后切换到该幻灯片(必填) |
aria-label | string | 'Slide {index}' | 无障碍标签,当前项会附加 `aria-current="true"` |
onClick | MouseEventHandler<HTMLButtonElement> | - | 点击时触发的额外回调,调用 `preventDefault()` 可阻止切换 |
type | string | 'button' | 按钮类型 |
className | string | - | 自定义类名(组件已附带 `data-bs-target` 以命中 Bootstrap 的指示器样式) |
...rest | ButtonHTMLAttributes | - | 透传原生 button 元素的所有属性 |
CarouselControl
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
direction | CarouselDirection | - | 控制方向,`"prev"` 渲染上一张按钮,`"next"` 渲染下一张按钮(必填) |
label | string | 'Previous' | 'Next' | 按钮的读屏文本,渲染为 `visually-hidden` 文本 |
disabled | boolean | - | 是否禁用,默认在只有一张幻灯片、或 `wrap` 为 `false` 且已到达边界时自动禁用 |
children | ReactNode | - | 自定义按钮内容,未提供时渲染 Bootstrap 的方向图标与读屏文本 |
onClick | MouseEventHandler<HTMLButtonElement> | - | 点击时触发的额外回调,调用 `preventDefault()` 可阻止切换 |
className | string | - | 自定义类名 |
...rest | ButtonHTMLAttributes | - | 透传原生 button 元素的所有属性 |
CarouselCaption
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
children | ReactNode | - | 标题内容,通常为标题与描述文本 |
className | string | - | 自定义类名,可配合 `d-none d-md-block` 在小屏隐藏 |
...rest | HTMLAttributes | - | 透传原生 div 元素的所有属性 |
Type Definitions
CarouselDirection
轮播切换方向类型
export type CarouselDirection = 'next' | 'prev';CarouselAnimationStatus
轮播过渡状态类型,由 Reducer 驱动:空闲、已就位(等待双 RAF)、滑动中
export type CarouselAnimationStatus = 'idle' | 'prepared' | 'sliding';CarouselItemRole
幻灯片在当前过渡中的角色类型,作为 `data-role` 输出到 DOM 供 CSS 使用
export type CarouselItemRole = 'active' | 'entering' | 'inactive' | 'leaving';CarouselRide
自动播放策略类型
export type CarouselRide = 'carousel' | boolean;CarouselPause
自动播放暂停策略类型
export type CarouselPause = 'hover' | false;CarouselCssProperties
轮播支持的自定义 CSS 变量,均以 `--rbs-` 前缀命名
export type CarouselCssProperties = {
'--rbs-carousel-control-disabled-opacity'?: number | string;
'--rbs-carousel-control-duration'?: string;
'--rbs-carousel-duration'?: string;
'--rbs-carousel-easing'?: string;
'--rbs-carousel-indicator-duration'?: string;
'--rbs-carousel-slide-offset'?: string;
} & CSSProperties;CarouselProps
Carousel 组件属性接口
export interface CarouselProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onSelect'> {
activeIndex?: number;
children?: ReactNode;
className?: string;
defaultActiveIndex?: number;
duration?: number;
fade?: boolean;
interval?: null | number;
keyboard?: boolean;
onSelect?: (index: number, direction: CarouselDirection) => void;
onSlid?: (index: number, direction: CarouselDirection) => void;
onSlide?: (index: number, direction: CarouselDirection) => void;
pause?: CarouselPause;
ride?: CarouselRide;
slide?: boolean;
style?: CarouselCssProperties;
touch?: boolean;
wrap?: boolean;
}CarouselInnerProps
Carousel 幻灯片容器属性接口
export interface CarouselInnerProps extends HTMLAttributes<HTMLDivElement> {
children?: ReactNode;
className?: string;
}CarouselItemProps
Carousel 幻灯片属性接口
export interface CarouselItemProps extends HTMLAttributes<HTMLDivElement> {
children?: ReactNode;
className?: string;
index?: number;
interval?: number;
}CarouselIndicatorsProps
Carousel 指示器容器属性接口
export interface CarouselIndicatorsProps extends HTMLAttributes<HTMLDivElement> {
children?: ReactNode;
className?: string;
labels?: string[];
}CarouselIndicatorProps
Carousel 单个指示器属性接口
export interface CarouselIndicatorProps extends ButtonHTMLAttributes<HTMLButtonElement> {
children?: ReactNode;
className?: string;
index: number;
}CarouselControlProps
Carousel 控制按钮属性接口
export interface CarouselControlProps extends ButtonHTMLAttributes<HTMLButtonElement> {
children?: ReactNode;
className?: string;
direction: CarouselDirection;
label?: string;
}CarouselCaptionProps
Carousel 标题属性接口
export interface CarouselCaptionProps extends HTMLAttributes<HTMLDivElement> {
children?: ReactNode;
className?: string;
}CarouselContextValue
Carousel 上下文,可通过 `useCarousel()` 在子组件中读取状态与控制方法
export interface CarouselContextValue {
activeIndex: number;
autoPlaying: boolean;
direction: CarouselDirection | null;
duration: number;
fade: boolean;
goTo: (index: number, direction?: CarouselDirection) => void;
itemCount: number;
next: () => void;
notifySlideEnd: () => void;
pause: () => void;
paused: boolean;
pendingIndex: null | number;
play: () => void;
prev: () => void;
registerItemInterval: (index: number, interval: number | undefined) => void;
setItemCount: (count: number) => void;
status: CarouselAnimationStatus;
wrap: boolean;
}