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

一个头像图片滚动轮播组件(React实现)

遇到一个效果,组件库里没有现成能用的组件,于是手搓了一个,传入图片url列表,和其他配置项即可直接使用。

轮播效果

头像轮播效果

实现思路

假设共有10张图片轮流滚动,轮播图展示3张图片。给正在轮播的图片绑定visible类,轮播过的图片绑定left类,待轮播的下一个图片绑定right。其中,绑定了visible类的图片以此从左往右排开,绑定了left类的在左侧并且隐藏,绑定了right的在右侧并隐藏(分左右是为了实现在右侧出现、在左侧消失的动画效果)。

  .visible {transform: translateX(calc(var(--index) * @image-width * (1 - var(--overlap))));z-index: calc(var(--index) + 1);opacity: 1;}.left {transform: translateX(-30px);z-index: 1;opacity: 0;}.right {transform: translateX(calc(var(--number) * @image-width * (1 - var(--overlap))));z-index: 1;opacity: 0;}

初始时,给10张图片分别绑定上不同的类,每次将这些类依次向后调整一格,最后的类挪到最前面。只有绑定了visible类的才会显示。

图片图片1图片2图片3图片4图片5图片6图片10
初始时visiblevisiblevisiblerightleftleftleft
第二leftvisiblevisiblevisiblerightleftleft
第三leftleftvisiblevisiblevisiblerightleft

代码

核心代码

新建一个组件,编写tsx代码

import { useCallback, useEffect, useRef, useState } from 'react';
import './index.less';interface ImageBannerProps {imagesData: string[];visibleNumber?: number; // 可以看见的数量overlapRate?: number; // 重叠率,默认值0.6interval?: number; // 间隔时间imageSize?: string; // 尺寸
}const ImageBanner: React.FC<ImageBannerProps> = (props) => {const { visibleNumber = 3, overlapRate = 0.3, interval = 1000, imageSize = '40px' } = props;let { imagesData } = props;// 复制到长度>=5,轮播组件最小长度要求while (imagesData.length && imagesData.length < 5) {imagesData = imagesData.concat(imagesData);}let initClassList = Array.from({ length: visibleNumber - 1 },(_, index) => `visible-${index + 1}`,);initClassList = [...initClassList, 'right', 'visible-0'];// 例如当visibleNumber=3时,初始值为["visible-1", "visible-2", "right", "visible-0"]const [classList, setClassList] = useState<string[]>(initClassList); // 每个图片的class,通过改变class更改样式const imgListRef = useRef<HTMLDivElement>(null);const initialize = useCallback((classList: string[]) => {if (imgListRef.current) {const imgList = Array.from(imgListRef.current.children);for (let i = 0; i < imgList.length; i++) {if (classList[i].includes('visible')) {const match = classList[i].match(/visible-(\d+)/); // 提取数字imgList[i].className = 'imgBannerItem visible';if (match) {(imgList[i] as HTMLDivElement).style.setProperty('--index', match[1]);}} else {imgList[i].className = 'imgBannerItem ' + classList[i];}}}}, []);const next = useCallback(() => {setClassList((prev) => {const newClassList = [...prev];newClassList.unshift(newClassList.pop()!);initialize(newClassList);return newClassList;});}, [initialize]);useEffect(() => {if (imagesData.length < 1) {return;}let timer;if (imgListRef.current) {const imgList = imgListRef.current.children;for (let i = 0; i < visibleNumber - 1; i++) {imgList[i].className = 'imgBannerItem ' + classList[i];}imgList[visibleNumber].className = 'imgBannerItem ' + classList[visibleNumber];const fillLeft = Array(imagesData.length - visibleNumber - 1).fill('left'); // 填入class为leftconst newClassList = [...classList.slice(0, visibleNumber),...fillLeft,...classList.slice(visibleNumber),];setClassList(newClassList);initialize(newClassList);timer = setInterval(next, interval);}return () => {if (timer) {clearInterval(timer);}};}, []);if (imagesData.length < 1) {return null;}return (<divclassName="imgBannerContainer"ref={imgListRef}style={{'--number': visibleNumber,'--overlap': overlapRate,'--size': imageSize,} as React.CSSProperties}>{imagesData.map((item, idx) => (<img className="imgBannerItem" src={item} alt="" key={idx} />))}</div>);
};export default ImageBanner;

样式代码

less代码

@image-width: var(--size);
@image-height: var(--size);.imgBannerContainer {width: 100%;height: 100%;position: relative;.visible {transform: translateX(calc(var(--index) * @image-width * (1 - var(--overlap))));z-index: calc(var(--index) + 1);opacity: 1;}.left {transform: translateX(-30px);z-index: 1;opacity: 0;}.right {transform: translateX(calc(var(--number) * @image-width * (1 - var(--overlap))));z-index: 1;opacity: 0;}
}.imgBannerItem {width: @image-width;height: @image-height;position: absolute;top: 0;transition: 0.3s;border-radius: 50%;border: 2px solid #fff;
}

使用

引入组件,传入图片列表进行使用

import ImageBanner from "../ImageBanner";const urlList = ["url1","url2","url3","url4","url5",	
];const Index = () => {return ( <><div style={{width: 300, height: 40, marginLeft: 20}}><ImageBanner imagesData={urlList} /></div></>);
}export default Index;
http://www.dtcms.com/a/351348.html

相关文章:

  • vscode有的结构体不能补全,有的可以补全问题的解决.
  • 校园资讯平台|校园资讯平台系统|基于java和小程序的校园资讯平台设计与实现(源码+数据库+文档)
  • 《数据之心》——鱼小妖的觉醒(童年篇)
  • 【国密证书】CentOS 7 安装 GmSSL 并生成国密证书
  • SpringBoot启动优化
  • 肌肉力量训练
  • 【C语言练习】汉诺塔
  • 金融市场微观行为分析结合深度学习的大单过滤与短期价格预测框架
  • 【资源分享】破解极域电子教室
  • 【云计算】云原生(Cloud Native)
  • 三、显示3D文字
  • 【车载开发系列】CS+ for CC开发环境IDE
  • 探索 3D 模型格式:综合指南glTF/GLB 格式
  • CVPR论文速递 | DL3DV-10K:10K+真实场景,打破三维视觉数据荒!
  • Maya绑定基础:创建骨骼和蒙皮、蒙皮权重控制的两种方法
  • 当自然语言遇上数据库:Text2Sql.Net的MCP革命如何重新定义开发者与数据的交互方式
  • 腾讯云DTS数据库迁移底层原理与实战解析
  • 云上“安全管家”|移动云以云安全中心为企业数字化升级保驾护航
  • MySQL 面试题系列(三)
  • 模块 PCB 制造:高频场景下的工艺难点与猎板质量管控体系
  • CentOS 7 服务器初始化完整流程
  • 文献阅读笔记【雷达辐射源识别】:Recognition of Unknown Radar Emitters with Machine Learning
  • 2025.8.26周二 在职老D渗透日记day26:pikachu文件上传漏洞 前端验证绕过
  • Hive高阶函数之行转列JSON数据解析
  • php程序设计之基于PHP的手工艺品销售网站/基于php在线销售系统/基于php在线购物商城系统
  • Redis之Keys命令和Scan命令
  • 后端Web实战-部门管理开发
  • BA 楼宇自控系统 + AI:重构楼宇设备管理的 “智能决策” 体系
  • 『专利好药用力心脑血管健康』——爱上古中医(28)(健康生活是coder抒写优质代码的前提条件——《黄帝内经》伴读学习纪要)
  • 阿里云 ECS 可观测性最佳实践