React SlideInWrapper组件异常:仅显示首个子元素且无过渡效果
问题描述
预期效果
我希望SlideInWrapper的子元素能从屏幕外交替从左右两侧滑入,且带有轻微延迟,避免所有元素同时触发动效。
当前问题
我的代码仅显示第一个子元素<p>Element 1</p>,且该元素目前没有过渡效果。
主组件代码
import React, { useEffect, useRef } from "react"; import styles from "../styles/SlideInWrapper.module.css"; // Make sure to create this CSS module for styling const SlideInWrapper = ({ children, delay = 300 }) => { const wrapperRef = useRef(null); useEffect(() => { const elements = wrapperRef.current.children; const numElements = elements.length; const handleTransitionEnd = (index) => { const currentElement = elements[index]; if (index < numElements - 1) { const nextIndex = index + 1; const nextElement = elements[nextIndex]; setTimeout(() => { nextElement.style.transition = "transform 0.5s ease"; nextElement.style.transform = "translateX(0)"; }, delay); } }; for (let i = 0; i < numElements; i++) { const element = elements[i]; element.style.transition = "transform 0.5s ease"; if (i % 2 === 0) { element.style.transform = "translateX(-100%)"; } else { element.style.transform = "translateX(100%)"; } element.addEventListener("transitionend", () => handleTransitionEnd(i)); } const initialElement = elements[0]; initialElement.style.transform = "translateX(0)"; return () => { for (let i = 0; i < numElements; i++) { const element = elements[i]; element.removeEventListener("transitionend", handleTransitionEnd); } }; }, [delay]); return ( <div className={styles["slide-in-wrapper"]} ref={wrapperRef}> {children} </div> ); }; export default SlideInWrapper;
CSS代码
/* Cool slide in wrapper animation */ .slide-in-wrapper { display: flex; flex-direction: column; } .slide-in-wrapper > * { width: 100%; opacity: 0; transition: transform 0.5s ease, opacity 0.5s ease; } .slide-in-wrapper > *:nth-child(odd) { transform: translateX(-100%); } .slide-in-wrapper > *:nth-child(even) { transform: translateX(100%); } .slide-in-wrapper > *:nth-child(1) { transform: translateX(0); opacity: 1; }
预期实现用法
<SlideInWrapper> <div>Element 1</div> <div>Element 2</div> <div>Element 3</div> {/* Add more elements here */} </SlideInWrapper>
修复方案
问题根源是CSS与JS样式冲突、事件绑定/清理逻辑错误,以下是针对性修复:
1. 重构CSS样式
去掉硬编码的第一个元素样式,改用类来管控动画状态,避免内联样式覆盖:
/* Cool slide in wrapper animation */ .slide-in-wrapper { display: flex; flex-direction: column; } .slide-in-wrapper > * { width: 100%; opacity: 0; transition: transform 0.5s ease, opacity 0.5s ease; } .slide-in-wrapper > *.slide-in-left { transform: translateX(-100%); } .slide-in-wrapper > *.slide-in-right { transform: translateX(100%); } .slide-in-wrapper > *.active { transform: translateX(0); opacity: 1; }
2. 修复组件逻辑
用CSS类替代内联样式,修复事件解绑问题,统一控制动画触发顺序:
import React, { useEffect, useRef } from "react"; import styles from "../styles/SlideInWrapper.module.css"; const SlideInWrapper = ({ children, delay = 300 }) => { const wrapperRef = useRef(null); useEffect(() => { const elements = Array.from(wrapperRef.current.children); const numElements = elements.length; // 初始化所有元素的待动画位置 elements.forEach((el, index) => { el.classList.add(index % 2 === 0 ? styles["slide-in-left"] : styles["slide-in-right"]); }); // 触发指定索引元素的动画 const triggerNextElement = (index) => { if (index >= numElements) return; elements[index].classList.add(styles["active"]); }; // 监听动画结束,触发下一个元素 const handleTransitionEnd = (e) => { const currentIndex = elements.indexOf(e.target); setTimeout(() => triggerNextElement(currentIndex + 1), delay); }; // 绑定事件 elements.forEach(el => el.addEventListener("transitionend", handleTransitionEnd)); // 启动第一个元素动画 triggerNextElement(0); // 清理事件监听 return () => { elements.forEach(el => el.removeEventListener("transitionend", handleTransitionEnd)); }; }, [delay]); return ( <div className={styles["slide-in-wrapper"]} ref={wrapperRef}> {children} </div> ); }; export default SlideInWrapper;
修复说明
- 用CSS类管理动画状态,彻底解决内联样式与CSS规则的冲突
- 事件绑定使用具名函数,确保组件卸载时能正确清理监听
- 统一通过
active类触发滑入+显示的组合动画 - 按顺序触发动画:第一个元素挂载后立即启动,后续元素在前一个动画结束后延迟触发
内容的提问来源于stack exchange,提问作者Wayne
相关产品推荐
相关产品推荐

