React Cover Flow轮播组件CSS过渡异常:最后元素无过渡
Cover Flow轮播组件过渡异常问题解决
我正在开发一个带Cover Flow效果的轮播组件,页面固定渲染3个元素并支持循环切换。目前遇到CSS过渡不符合预期的问题:点击切换下一张时,中间轮播项应过渡到左侧位置,左侧项过渡到右侧位置,右侧项过渡到中间位置,但右侧元素没有过渡效果,直接突兀地渲染在屏幕上。

相关代码
Carousel.tsx
type CarouselProps = { children: | React.ReactElement<CarouselItemProps> | React.ReactElement<CarouselItemProps>[]; className?: React.HTMLAttributes<HTMLDivElement>["className"]; }; const Carousel = ({ children, className }: CarouselProps) => { const carouselItems = Children.toArray(children); const [currentIndex, setCurrentIndex] = useState<number>(0); const prevIndex = (currentIndex - 1 + carouselItems.length) % carouselItems.length; const nextIndex = (currentIndex + 1) % carouselItems.length; const getCarouselItemsToShow = () => { if (carouselItems.length < 3) return carouselItems; const indexes = [prevIndex, currentIndex, nextIndex]; return indexes.map((index) => carouselItems[index]); }; const handleClickPrev = () => { setCurrentIndex( (prevState) => (prevState - 1 + carouselItems.length) % carouselItems.length ); }; const handleClickNext = () => { setCurrentIndex((prevState) => (prevState + 1) % carouselItems.length); }; return <div className="relative flex align-items h-[279px] mb-[20px] border border-white *:absolute *:top-[50%] *:-translate-y-1/2 *:-translate-x-1/2 *:transition-all *:duration-1000"> {getCarouselItemsToShow().map((item, index) => { return React.cloneElement( item as React.ReactElement<CarouselItemProps>, { className: index === 1 ? "w-[419px] left-[50%] z-10" : "w-[297px] opacity-80 first:left-[30%] last:left-[70%]", } ); })} </div> [...]}
CarouselItem.tsx
export type CarouselItemProps = { imgSrc: string; description: string; className?: React.HTMLAttributes<HTMLDivElement>["className"]; }; const CarouselItem = ({ imgSrc, className }: CarouselItemProps) => { return ( <Image src={imgSrc} alt="" width={419} height={275} className={"rounded-[40px] " + className} /> ); }; export default CarouselItem;
App.tsx
[...] <Carousel> <CarouselItem imgSrc={data.jobs[0].projects[0].imageSrc} description={data.jobs[0].projects[0].description} /> <CarouselItem imgSrc={data.jobs[0].projects[1].imageSrc} description={data.jobs[0].projects[1].description} /> <CarouselItem imgSrc={data.jobs[0].projects[2].imageSrc} description={data.jobs[0].projects[2].description} /> </Carousel> [...]}
问题原因
- React元素复用逻辑错误:当前渲染时没有给轮播项绑定唯一
key,React会根据渲染顺序(map的index)复用组件,而非轮播项本身。切换时新的右侧元素会被React识别为新元素,直接挂载到DOM,没有过渡过程。 - 伪类样式突变:使用
first:和last:这类Tailwind伪类,切换时数组顺序变化会导致伪类对应的元素突然变更样式,无法触发平滑过渡。
解决方案
1. 绑定唯一key确保元素复用
在克隆元素时,传入轮播项的原始索引作为key,让React能正确识别每个元素:
{getCarouselItemsToShow().map((item, index) => { // 获取当前项的原始索引 const originalIndex = [prevIndex, currentIndex, nextIndex][index]; return React.cloneElement( item as React.ReactElement<CarouselItemProps>, { key: originalIndex, className: getPositionClass(index), } ); })}
2. 替换伪类为明确的位置样式函数
提取样式逻辑为函数,避免伪类带来的样式突变:
const getPositionClass = (positionIndex: number) => { switch(positionIndex) { case 0: // 左侧项 return "w-[297px] opacity-80 left-[30%]"; case 1: // 中间项 return "w-[419px] left-[50%] z-10"; case 2: // 右侧项 return "w-[297px] opacity-80 left-[70%]"; default: return ""; } };
修改后的核心渲染代码
const getPositionClass = (positionIndex: number) => { switch(positionIndex) { case 0: return "w-[297px] opacity-80 left-[30%]"; case 1: return "w-[419px] left-[50%] z-10"; case 2: return "w-[297px] opacity-80 left-[70%]"; default: return ""; } }; return ( <div className="relative flex align-items h-[279px] mb-[20px] border border-white *:absolute *:top-[50%] *:-translate-y-1/2 *:-translate-x-1/2 *:transition-all *:duration-1000"> {getCarouselItemsToShow().map((item, index) => { const originalIndex = [prevIndex, currentIndex, nextIndex][index]; return React.cloneElement( item as React.ReactElement<CarouselItemProps>, { key: originalIndex, className: getPositionClass(index), } ); })} </div> );
内容的提问来源于stack exchange,提问作者Felipe Eduardo
相关产品推荐
相关产品推荐

