You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

React加载组件时禁用动画,仅在响应式断点触发动画

解决React组件首次加载时动画自动触发的问题

这个问题我之前也碰到过!核心原因是首次加载时你的响应式逻辑会直接检查当前窗口尺寸,要是刚好小于800px,动画触发条件就满足了,自然会自动播放。咱们可以通过区分「首次加载」和「用户主动调整窗口尺寸」这两种场景来解决,给你两种方案适配不同的组件类型:

方案一:类组件(对应你提到的带有render()的Test组件)

我们可以添加一个状态标记组件是否完成首次挂载,只有挂载完成后,窗口尺寸变化触发断点时才执行动画:

class Test extends React.Component {
  // 初始化状态:当前是否为移动端尺寸,以及是否完成首次挂载
  state = {
    isMobile: window.innerWidth < 800,
    hasMounted: false
  };

  componentDidMount() {
    // 挂载后添加resize监听
    window.addEventListener('resize', this.handleResize);
    // 标记组件已完成首次挂载
    this.setState({ hasMounted: true });
  }

  componentWillUnmount() {
    // 组件卸载时移除监听,避免内存泄漏
    window.removeEventListener('resize', this.handleResize);
  }

  handleResize = () => {
    const newIsMobile = window.innerWidth < 800;
    // 仅当组件已挂载,且尺寸状态发生变化时,才触发动画
    if (this.state.hasMounted && newIsMobile !== this.state.isMobile) {
      this.setState({ isMobile: newIsMobile }, () => {
        // 这里执行你的动画逻辑
        this.triggerDivAnimation();
      });
    } else {
      // 只是更新尺寸状态,不触发动画
      this.setState({ isMobile: newIsMobile });
    }
  };

  triggerDivAnimation = () => {
    // 获取main-content下的div,添加动画类
    const targetDivs = document.querySelectorAll('.main-content div');
    targetDivs.forEach(div => div.classList.add('rearrange-animation'));
    
    // 动画结束后移除类,方便下次触发时再次生效
    setTimeout(() => {
      targetDivs.forEach(div => div.classList.remove('rearrange-animation'));
    }, 800); // 这里的时间要和你的CSS动画时长一致
  };

  render() {
    const { isMobile } = this.state;
    return (
      <div className={`main-content ${isMobile ? 'mobile-flex-layout' : ''}`}>
        {/* 你的div内容 */}
        <div>区块1</div>
        <div>区块2</div>
        <div>区块3</div>
      </div>
    );
  }
}

方案二:函数组件(如果后续重构为Hooks写法)

useRef来标记是否完成首次挂载,结合useEffect处理resize监听:

import React, { useState, useEffect, useRef } from 'react';

const Test = () => {
  const [isMobile, setIsMobile] = useState(window.innerWidth < 800);
  // useRef存储挂载状态,不会触发组件重渲染
  const hasMounted = useRef(false);

  useEffect(() => {
    const handleResize = () => {
      const newIsMobile = window.innerWidth < 800;
      if (hasMounted.current && newIsMobile !== isMobile) {
        setIsMobile(newIsMobile);
        triggerDivAnimation();
      } else {
        setIsMobile(newIsMobile);
      }
    };

    window.addEventListener('resize', handleResize);
    // 挂载完成后更新标记
    hasMounted.current = true;

    // 清理函数:移除监听
    return () => window.removeEventListener('resize', handleResize);
  }, [isMobile]);

  const triggerDivAnimation = () => {
    const targetDivs = document.querySelectorAll('.main-content div');
    targetDivs.forEach(div => div.classList.add('rearrange-animation'));
    setTimeout(() => {
      targetDivs.forEach(div => div.classList.remove('rearrange-animation'));
    }, 800);
  };

  return (
    <div className={`main-content ${isMobile ? 'mobile-flex-layout' : ''}`}>
      <div>区块1</div>
      <div>区块2</div>
      <div>区块3</div>
    </div>
  );
};

export default Test;

额外优化建议

如果你的动画是通过CSS类控制的,也可以在render时直接根据挂载状态和尺寸状态决定是否添加动画类,比如:

{/* 类组件render里的main-content */}
<div className={`main-content ${isMobile ? 'mobile-flex-layout' : ''} ${this.state.hasMounted && isMobile ? 'animate-on-resize' : ''}`}>

这样能更精准地控制动画的触发时机,避免不必要的DOM操作。

内容的提问来源于stack exchange,提问作者Jolly

火山引擎 最新活动