You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 22:24:58