当前位置: 首页 > news >正文

React+TS编写轮播图

当前轮播图存在部分问题,一次循环结束,进入下一次需要点击两次(所以动画效果上点击第二次才出现)


轮播图:实现无限循环轮播图的关键在于"视觉欺骗"——我们在实际数据的前后各添加部分数据副本,当滚动到边缘时快速而无缝地跳转到另一端,从而创造出无限循环的视觉效果。

理想效果

轮播图理想效果:呈现多个元素盒子,并且首元素默认初次呈现居中效果,通过左右按钮控制轮播图的滑动,滑动一次下一个元素又再次居中,居中元素有一个居中动画效果

静态效果:

逻辑思路

初始准备

  1. 首先在scss里面将track盒子居中,最外层盒子设置overflow:hidden,注意:这里尽量不要去使用transform去让track居中,不然后续ts去控制盒子移动这个效果会被抵消
  2. 当前居中的元素并非首元素,是track盒子里中的中间元素,给track中间数据的midOder标记为为0因为这是实际的中间元素
  3. 想要首元素居中,在初始化的时候需要进行一次transform去移动使首元素居中

控制移动

  1. 计算滑动距离=两个盒子的left距离,这里采用clienWidth因为在我自己项目中是响应式布局,使用clienWidth更适合
  2. 然后给左右移动按钮添加点击事件,去更新currentIndex
  3. 普通移动:添加移动效果动画,并且移动currentIdex*sliWidth(transform的效果是覆盖的,会覆盖初始化的首元素为中点,所以track真实的位置初始是真实中间元素是起点也就是midOder为0的元素是起点,所以是相对于这个起点进行的移动)

无限循环效果

  1. 正常普通移动到第一个克隆dom,然后下一次点击transition为none,视觉上用户看不到已经移动到了下一次循环中
  2. 然后调用setCurentIndex去更新当前中间元素标记
  3. 与前面普通移动放在一起,形成判断条件,到达了边缘判断,就进行视觉欺骗

添加中间动画

  1. 判断当前中间位置currentIndex是否等于元素的midOrder,是的话添加中间效果动画

数据结构准备

const carouselData = [{title: '00',midOrder: -2,},{title: '11',midOrder: -1,},{title: '22',midOrder: 0,},{title: '33',midOrder: 1,},{title: '44',midOrder: 2,},
];

组件实现步骤

1. 扩展数据创建"视觉循环"

const slides = [carouselData[carouselData.length - 3],carouselData[carouselData.length - 2],carouselData[carouselData.length - 1],...carouselData,carouselData[0],carouselData[1],carouselData[2],
];

在原始数据前后各添加3个数据项,这样当滚动到"边缘"时,可以无缝跳转。

2. 状态管理

const [currentIndex, setCurrentIndex] = useState(-2);
const [slideWidth, setSlideWidth] = useState(0);
const trackRef = useRef<HTMLDivElement>(null);
  • currentIndex 表示当前中心项的索引

  • slideWidth 存储每个轮播项的宽度

  • trackRef 用于操作轮播轨道DOM元素

3. 计算轮播项宽度

useEffect(() => {const items = trackRef.current?.querySelectorAll('.activities-recent-item');if (!items || items.length < 2) return;
​const first = items[0].getBoundingClientRect();const second = items[1].getBoundingClientRect();setSlideWidth(first.left - second.left);
}, []);

这个效果通过比较相邻两个轮播项的位置来计算单个项的宽度。

4. 处理导航点击

const handleDirection = (dir: 'left' | 'right') => {if (dir === 'left') {setCurrentIndex((prev) => prev - 1);} else {setCurrentIndex((prev) => prev + 1);}
};

点击左右按钮时,更新当前索引。

5. 无限循环修正

useEffect(() => {const track = trackRef.current;if (!track) return;
​if (currentIndex === -4) {track.style.transition = 'none';track.style.transform = `translateX(${2 * slideWidth}px)`;setCurrentIndex(2);} else if (currentIndex === 4) {track.style.transition = 'none';track.style.transform = `translateX(${-2 * slideWidth}px)`;setCurrentIndex(-2);} else {track.style.transition = 'transform 0.4s ease';track.style.transform = `translateX(${currentIndex * slideWidth}px)`;}
}, [currentIndex]);

当滚动到边缘时:

  1. 禁用过渡动画

  2. 立即跳转到另一端

  3. 重新启用动画

6. 渲染组件

return (<><div className="rencent-to-left recent-to-button" onClick={() => handleDirection('left')}><i className="iconfont icon-zuojiantou"></i></div>
​<div className="activities-recent-container"><div ref={trackRef} className="activities-recent-box track-box">{slides.map((item) => (<div className={`activities-recent-item ${item.midOrder === currentIndex ? 'mid-active' : ''}`}>{item.title}</div>))}</div></div>
​<div className="rencent-to-right recent-to-button" onClick={() => handleDirection('right')}><i className="iconfont icon-youjiantou"></i></div></>
);

关键点总结

  1. 数据扩展:通过在原始数据前后添加副本,实现视觉上的无限循环

  2. 无缝跳转:当滚动到边缘时,禁用动画并立即跳转

  3. 精确计算:动态计算轮播项宽度确保滚动精度

  4. 状态管理:使用React状态控制当前显示项

  5. CSS过渡:通过CSS实现平滑的滚动效果

 

http://www.xdnf.cn/news/42427.html

相关文章:

  • FreeSWITCH 简单图形化界面41 - 批量SIP视频呼叫测试
  • 游戏引擎学习第237天:使用 OpenGL 显示图像
  • 绝对路径与相对路径
  • 【C++】多态 - 从虚函数到动态绑定的核心原理
  • HTTP:十.cookie机制
  • Kotlin实现Android应用保活方案
  • 基于maven-jar-plugin打造一款自动识别主类的maven打包插件
  • 【C++详解】C++入门(一)
  • PyTorch 深度学习实战(39):归一化技术对比(BN/LN/IN/GN)
  • 基于Docker+k8s集群的web应用部署与监控
  • 操作系统是如何运行的?
  • 【图像处理基石】什么是去马赛克算法?
  • 维普期刊(瑞数6)分析
  • 什么是 IDE?集成开发环境的功能与优势
  • iOS 应用性能测试工具对比:Xcode Instruments、克魔助手与性能狗
  • 指针(3)
  • 常用算法解析:从基础排序到图论应用
  • 【Hot100】 240. 搜索二维矩阵 II
  • 霍尔三维结构
  • QML中日期处理类
  • prim最小生成树+最大生成树【C++】板子题
  • 缓存 --- 缓存击穿, 缓存雪崩, 缓存穿透
  • 【连接池-55】MySQL数据库连接池:原理、实现与最佳实践
  • 缓存 --- Redis的三种高可用模式
  • 14【结构体 Struct】定义、实例化与方法:封装数据与行为
  • css3新特性第三章(文本属性)
  • Linux下加载可执行文件所在目录下的so的方法
  • 实操基于MCP驱动的 Agentic RAG:智能调度向量召回或者网络检索
  • 从零开始详细讲解 Boost.Asio
  • Vue3集成Element Plus完整指南:从安装到主题定制上