ImageViewer
基础反馈基于 Bootstrap 5 的图片查看组件族,通过 Image 提供点击预览的缩略图,ImageGroup 将多张图片聚合为分组预览,ImageViewer 提供全屏灯箱查看器,支持缩放、旋转、拖拽平移、键盘操作、缩略图导航、全屏与下载,并可通过受控模式与 useImageViewer 钩子灵活组合自定义工具栏
Component Demo
Basic usage and examples of the ImageViewer component
基础示例
Image 默认开启点击预览,悬停时显示缩放遮罩,点击后在灯箱中查看大图,支持缩放、旋转与全屏
图片样式
`fluid`、`rounded`、`roundedCircle`、`thumbnail` 对应 Bootstrap 图片工具类,`preview=` 时渲染原生 img 元素且不启用预览
分组预览
ImageGroup 内的 Image 点击后共享同一个查看器,从当前图片开始并可在分组内前后切换
多图查看器
多图时默认显示计数器、左右切换按钮与底部缩略图,点击图片以外的遮罩区域或按 Esc 关闭, `loop` 开启首尾循环,图片对象的 `caption` 显示为底部说明
缩放与旋转
滚轮或 +/- 键缩放、双击快速切换 1x/2x、放大后拖拽平移,工具栏或 R 键旋转,0 键复位
工具栏定制
通过数组按顺序挑选按钮,此示例移除了下载与全屏;`toolbar=` 则完全隐藏工具栏
自定义组合
关闭内置工具栏与切换按钮,通过 `children` 底部插槽和 `useImageViewer` 钩子完全自定义操作区
受控模式
`open`/`index` 与 `onOpenChange`/`onIndexChange` 组合实现完全受控,外部状态随切换实时同步
API Documentation
Complete API reference for the ImageViewer component
Props
Image
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
alt | string | '' | 图片替代文本,未提供时预览按钮使用默认无障碍标签 |
fluid | boolean | false | 是否应用 `img-fluid` 流式布局 |
preview | boolean | true | 是否启用点击预览,`false` 时渲染原生 img 元素 |
previewSrc | string | - | 预览使用的图片地址,默认与 `src` 相同 |
rounded | boolean | false | 是否应用 `rounded` 圆角样式 |
roundedCircle | boolean | false | 是否应用 `rounded-circle` 圆形样式 |
showPreviewMask | boolean | true | 悬停或聚焦时是否显示预览遮罩 |
thumbnail | boolean | false | 是否应用 `img-thumbnail` 缩略图样式 |
viewerProps | ImageViewerGroupViewerProps | - | 透传给内部 ImageViewer 的配置,仅当 Image 独立使用(不在 ImageGroup 内)时生效 |
ImageGroup
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
as | ElementType | 'div' | 渲染的根元素类型 |
viewerProps | ImageViewerGroupViewerProps | - | 透传给分组 ImageViewer 的配置 |
ImageViewer
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
backdrop | boolean | 'static' | true | 遮罩行为:`true` 点击遮罩关闭、`'static'` 不响应点击、`false` 不渲染遮罩 |
children | ReactNode | - | 自定义底部内容,配合 `useImageViewer` 可组合自定义工具栏 |
defaultIndex | number | 0 | 非受控模式下初始显示的图片索引 |
defaultOpen | boolean | false | 非受控模式下初始是否打开 |
duration | number | 200 | 打开/关闭过渡时长(毫秒),跟随系统减少动态效果设置自动降为 0 |
images | ImageViewerSource[] | - | 图片列表,支持字符串地址或 `ImageViewerImage` 对象,必填 |
index | number | - | 受控模式下的当前索引,配合 `onIndexChange` 使用 |
keyboard | boolean | true | 是否启用键盘操作:Esc 关闭、左右方向键切换、+/- 缩放、0 复位、R 旋转 |
loop | boolean | false | 是否在首尾循环切换图片 |
maxZoom | number | 10 | 最大缩放倍数 |
minZoom | number | 0.5 | 最小缩放倍数 |
onImageError | (image, index, event) => void | - | 图片加载失败时的回调 |
onIndexChange | (index: number) => void | - | 当前图片索引变化时的回调 |
onOpenChange | (open: boolean) => void | - | 打开状态变化时的回调 |
open | boolean | - | 受控模式下的打开状态,配合 `onOpenChange` 使用 |
showCounter | boolean | 多图时为 true | 是否显示「当前 / 总数」计数器 |
showNav | boolean | 多图时为 true | 是否显示上一张/下一张切换按钮 |
showThumbnails | boolean | 多图时为 true | 是否显示底部缩略图导航条 |
toolbar | boolean | ImageViewerToolbarKey[] | true | 工具栏配置:`true` 显示全部按钮、`false` 隐藏、数组按给定顺序渲染指定按钮 |
zoomable | boolean | true | 是否启用缩放,关闭后按钮、滚轮与双击缩放均不可用 |
zoomStep | number | 0.25 | 每次缩放操作的步进倍数 |
Common Props
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
children | ReactNode | - | 子内容:ImageViewer 中作为底部自定义区域渲染 |
className | string | - | 自定义类名 |
...rest | HTMLAttributes | - | 透传原生元素属性(如 `style`、`aria-label` 等) |
Type Definitions
ImageProps
图片缩略图组件属性接口
export interface ImageProps extends ImgHTMLAttributes<HTMLImageElement> {
alt?: string;
fluid?: boolean;
preview?: boolean;
previewSrc?: string;
rounded?: boolean;
roundedCircle?: boolean;
showPreviewMask?: boolean;
thumbnail?: boolean;
viewerProps?: ImageViewerGroupViewerProps;
}ImageGroupProps
图片分组组件属性接口
export interface ImageGroupProps extends HTMLAttributes<HTMLElement> {
as?: ElementType;
children?: ReactNode;
className?: string;
viewerProps?: ImageViewerGroupViewerProps;
}ImageViewerProps
图片查看器组件属性接口
export interface ImageViewerProps extends Omit<
DialogHTMLAttributes<HTMLDialogElement>,
'children'
> {
backdrop?: boolean | 'static';
children?: ReactNode;
className?: string;
defaultIndex?: number;
defaultOpen?: boolean;
duration?: number;
images: ImageViewerSource[];
index?: number;
keyboard?: boolean;
loop?: boolean;
maxZoom?: number;
minZoom?: number;
onImageError?: (
image: ImageViewerImage,
index: number,
event: SyntheticEvent<HTMLImageElement>,
) => void;
onIndexChange?: (index: number) => void;
onOpenChange?: (open: boolean) => void;
open?: boolean;
showCounter?: boolean;
showNav?: boolean;
showThumbnails?: boolean;
toolbar?: boolean | ImageViewerToolbarKey[];
zoomable?: boolean;
zoomStep?: number;
}ImageViewerImage
查看器图片对象,支持描述文本与下载文件名
export interface ImageViewerImage {
alt?: string;
caption?: ReactNode;
name?: string;
src: string;
}ImageViewerSource
图片数据源类型,字符串或图片对象
export type ImageViewerSource = string | ImageViewerImage;ImageViewerToolbarKey
工具栏按钮键类型
export type ImageViewerToolbarKey =
| 'close'
| 'download'
| 'fullscreen'
| 'reset'
| 'rotateLeft'
| 'rotateRight'
| 'zoomIn'
| 'zoomOut';ImageViewerContextValue
查看器上下文值,`useImageViewer` 的返回值
export interface ImageViewerContextValue {
close: () => void;
currentImage: ImageViewerImage;
currentIndex: number;
download: () => void;
imageCount: number;
isFullscreen: boolean;
next: () => void;
previous: () => void;
reset: () => void;
rotateLeft: () => void;
rotateRight: () => void;
rotation: ImageViewerRotation;
scale: number;
setIndex: (index: number) => void;
toggleFullscreen: () => void;
zoomIn: () => void;
zoomOut: () => void;
}