50天50个小项目 (React19 + Tailwindcss V4) ✨| ImageCarousel(图片轮播组件)
使用React19 和TailwindCSS 实现的图片轮播组件。主要功能包括:手动切换图片(上一张/下一张)、自动播放(3秒间隔)、平滑过渡动画。组件采用React19 的useState管理状态,通过transform实现图片切换效果,并利用Tailwind CSS快速构建UI。
📅 今天我们继续 50 个小项目挑战!——ImageCarousel组件
仓库地址:https://gitee.com/hhm-hhm/50days50projects.git

构建一个简洁且功能齐全的图片轮播组件(Carousel)。该组件不仅支持手动切换上一张和下一张图片,还具备自动播放功能。
🌀 组件目标
- 实现自动播放和手动切换功能
- 组件结构清晰、易于扩展
- 使用
TailwindCSS快速构建 UI 样式
🔧 ImageCarousel.tsx组件实现
import React, { useState, useEffect, useRef } from 'react'
const ImageCarousel: React.FC = () => {
// 图片数组(可替换为实际数据)
const images = [
'https://picsum.photos/id/10/800/400',
'https://picsum.photos/id/11/800/400',
'https://picsum.photos/id/12/800/400',
'https://picsum.photos/id/13/800/400',
] as const
const [currentIndex, setCurrentIndex] = useState<number>(0)
const autoPlayTimerRef = useRef<NodeJS.Timeout | null>(null)
// 切换到上一张
const prevImage = () => {
setCurrentIndex((prev) => (prev - 1 + images.length) % images.length)
}
// 切换到下一张
const nextImage = () => {
setCurrentIndex((prev) => (prev + 1) % images.length)
}
// 启动自动轮播
const startAutoPlay = () => {
if (autoPlayTimerRef.current) return
autoPlayTimerRef.current = setInterval(() => {
nextImage()
}, 3000)
}
// 清除定时器
const clearAutoPlay = () => {
if (autoPlayTimerRef.current) {
clearInterval(autoPlayTimerRef.current)
autoPlayTimerRef.current = null
}
}
// 组件挂载时启动轮播,卸载时清除
useEffect(() => {
startAutoPlay()
return () => {
clearAutoPlay()
}
}, [])
return (
<div className="flex min-h-screen items-center justify-center bg-gray-900">
<div className="absolute top-1/2 left-1/2 h-[400px] w-[800px] -translate-x-1/2 -translate-y-1/2 overflow-hidden">
{/* 图片容器 */}
<div
className="flex h-full transition-transform duration-500 ease-in-out"
style={{ transform: `translateX(-${currentIndex * 100}%)` }}>
{images.map((src, index) => (
<img
key={index}
src={src}
alt={`Slide ${index + 1}`}
className="h-[400px] w-[800px] shrink-0 object-cover"
/>
))}
</div>
{/* 控制按钮 */}
<div className="absolute bottom-5 left-1/2 flex -translate-x-1/2 gap-5">
<button
onClick={prevImage}
className="cursor-pointer rounded border-none bg-[rgba(0,0,0,0.5)] px-4 py-2 text-white transition-colors hover:bg-[rgba(0,0,0,0.8)]"
aria-label="上一张">
上一张
</button>
<button
onClick={nextImage}
className="cursor-pointer rounded border-none bg-[rgba(0,0,0,0.5)] px-4 py-2 text-white transition-colors hover:bg-[rgba(0,0,0,0.8)]"
aria-label="下一张">
下一张
</button>
</div>
</div>
<div className="fixed right-20 bottom-5 z-100 text-2xl text-red-500">
CSDN@Hao_Harrision
</div>
</div>
)
}
export default ImageCarousel
🔄 关键差异总结
| 功能 | Vue 3 | React + TS |
|---|---|---|
| 响应式状态 | ref() |
useState() |
| 生命周期 | onMounted / onUnmounted |
useEffect(() => { ... }, []) |
| 定时器存储 | 模块变量 | useRef |
| 列表渲染 | v-for |
.map() |
| 内联样式 | :style |
style={{}} |
| 样式类名 | 直接写 | 相同(Tailwind 兼容) |
🔁 转换说明
1. 状态管理:ref → useState
| Vue | React |
|---|---|
const currentIndex = ref(0) |
const [currentIndex, setCurrentIndex] = useState(0) |
✅ 功能完全等价。
2. 生命周期:onMounted / onUnmounted → useEffect
Vue:
onMounted(() => startAutoPlay());
onUnmounted(() => clearInterval(autoPlayTimer));
React:
useEffect(() => {
startAutoPlay();
return () => clearAutoPlay(); // 清理函数 = onUnmounted
}, []);
✅ useEffect 的返回函数会在组件卸载时执行,等效于 onUnmounted。
3. 定时器管理:使用 useRef 存储 timer ID
- Vue 中直接用
let autoPlayTimer = null(模块作用域变量); - React 中必须用
useRef保存 timer,避免闭包问题且不触发重渲染:
const autoPlayTimerRef = useRef<NodeJS.Timeout | null>(null);
✅ 这是 React 中管理定时器、订阅等副作用的标准做法。
4. 自动轮播安全启动
const startAutoPlay = () => {
if (autoPlayTimerRef.current) return; // 防止重复启动
autoPlayTimerRef.current = setInterval(...);
};
✅ 避免多次点击或快速切换导致多个定时器并发。
5. JSX vs Template
| Vue | React |
|---|---|
<img v-for="..." :src="image" /> |
{images.map(...)} |
:style="{ transform: ... }" |
style={{ transform: ... }} |
✅ 所有逻辑一一对应。
6. 样式与布局优化
- 添加
flex-shrink-0到<img>:确保每张图保持800px宽度,不被 flex 压缩; - 使用
-translate-x-1/2 -translate-y-1/2实现绝对居中(与 Vue 一致); - 按钮添加
transition-colors提升交互体验; - 添加
alt属性符合可访问性规范。
7. 类型安全增强
- 使用
as const固定images数组,防止意外修改; - 明确
NodeJS.Timeout类型(Node 环境)或浏览器环境可用number,但在 Vite + TS 中通常兼容。
如果你在纯浏览器环境开发,也可写成:
const autoPlayTimerRef = useRef<number | null>(null);因为
setInterval在浏览器返回number。
但 Vite 默认支持 Node 类型,所以 NodeJS.Timeout 更通用。
✅ 功能验证
- 页面加载后自动轮播(3秒/张);
- 点击“上一张”/“下一张”可手动切换;
- 组件卸载时自动清除定时器(无内存泄漏);
- 图片水平滑动动画流畅;
- 响应式居中布局。
💡 扩展建议(可选)
- 添加指示器(dots)显示当前页;
- 支持传入
images作为 props; - 暂停自动播放(hover 时暂停);
- 键盘导航(← → 方向键)。
🎨 TailwindCSS 样式重点讲解
| 类名 | 作用 |
|---|---|
absolute |
将元素定位为绝对定位 |
top-1/2 left-1/2 |
设置元素相对于最近的定位祖先顶部和左侧对齐 |
-translate-x-1/2 -translate-y-1/2 |
将元素沿 X 轴和 Y 轴移动自身宽度和高度的一半,实现居中对齐 |
h-[400px] w-[800px] |
固定元素的高度和宽度 |
overflow-hidden |
隐藏超出容器的内容 |
transition-transform duration-500 ease-in-out |
添加变换属性的过渡动画,持续时间为 500ms,缓动效果为 ease-in-out |
object-cover |
保持图片比例并填充整个容器 |
hover:bg-[rgba(0,0,0,0.8)] |
设置鼠标悬停时的背景颜色为更深的半透明黑色 |
🦌 路由组件 + 常量定义
router/index.tsx 中 children数组中添加子路由
{
path: '/',
element: <App />,
children: [
...
{
path: '/ImageCarousel',
lazy: () =>
import('@/projects/ImageCarousel').then((mod) => ({
Component: mod.default,
})),
},
],
},
constants/index.tsx 添加组件预览常量
import demo35Img from '@/assets/pic-demo/demo-35.png'
省略部分....
export const projectList: ProjectItem[] = [
省略部分....
{
id: 35,
title: 'Image Carousel',
image: demo35Img,
link: 'ImageCarousel',
},
]
🚀 小结
通过这篇文章,我们使用 React19 和 TailwindCSS 创建一个功能完善的图片轮播组件。
你可以扩展这个基础的图片轮播组件:
✅ 添加指示器(Indicators):显示当前是第几张图片,支持点击切换。
✅ 触控滑动(Touch Support):支持在移动端通过滑动手势切换图片。
✅ 暂停自动播放:当鼠标悬停在轮播图上时暂停自动播放。
✅ 动态加载图片:从后端接口获取图片数据。
✅ 响应式设计:根据屏幕尺寸自适应轮播图宽度和高度。
📅 明日预告: 我们将完成Hoverboard组件,实现一个非常炫酷的鼠标悬浮彩虹轨迹。🚀
感谢阅读,欢迎点赞、收藏和分享 😊
原文链接:https://blog.csdn.net/qq_44808710/article/details/149549387
每天造一个轮子,码力暴涨不是梦!🚀
更多推荐



所有评论(0)