MST
星途 面试题库

面试题:React Hooks实现复杂动画序列的处理

在React项目中,要求实现一个动画序列,比如先让一个元素从左侧滑入,停顿2秒后再放大,最后旋转360度。请详细说明如何利用React的Hooks(如useState、useEffect、useRef等)来实现这个复杂的动画序列,包括如何控制动画的顺序、时间间隔以及动画的触发条件,给出较为完整的代码实现思路和关键代码。
27.3万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 状态管理:使用 useState 来管理动画的不同阶段状态,例如 isSlidingIn 表示是否正在从左侧滑入,isPaused 表示是否处于停顿阶段,isScaling 表示是否正在放大,isRotating 表示是否正在旋转。
  2. 动画触发条件:可以通过某个事件(如按钮点击)来触发动画序列。当触发事件发生时,设置 isSlidingIntrue,从而开始动画序列。
  3. 控制动画顺序和时间间隔:利用 useEffect 钩子函数来监听状态变化。当 isSlidingIn 变为 true 时,开始左侧滑入动画。在滑入动画结束后(可以通过 animationend 事件监听),设置 isPausedtrue,并通过 setTimeout 在2秒后将 isPaused 设置为 falseisScaling 设置为 true。同理,在放大动画结束后,设置 isRotatingtrue 开始旋转动画。
  4. 动画实现:使用CSS的 @keyframes 规则定义各个动画,通过 useRef 获取DOM元素并应用相应的动画类名。

关键代码

import React, { useState, useEffect, useRef } from'react';
import './styles.css';

const AnimationComponent = () => {
  const [isSlidingIn, setIsSlidingIn] = useState(false);
  const [isPaused, setIsPaused] = useState(false);
  const [isScaling, setIsScaling] = useState(false);
  const [isRotating, setIsRotating] = useState(false);
  const elementRef = useRef(null);

  const startAnimation = () => {
    setIsSlidingIn(true);
  };

  useEffect(() => {
    const handleAnimationEnd = (e) => {
      if (e.target === elementRef.current) {
        if (isSlidingIn) {
          setIsSlidingIn(false);
          setIsPaused(true);
          setTimeout(() => {
            setIsPaused(false);
            setIsScaling(true);
          }, 2000);
        } else if (isScaling) {
          setIsScaling(false);
          setIsRotating(true);
        }
      }
    };
    if (elementRef.current) {
      elementRef.current.addEventListener('animationend', handleAnimationEnd);
    }
    return () => {
      if (elementRef.current) {
        elementRef.current.removeEventListener('animationend', handleAnimationEnd);
      }
    };
  }, [isSlidingIn, isScaling]);

  return (
    <div>
      <button onClick={startAnimation}>开始动画</button>
      <div
        ref={elementRef}
        className={`animated-element ${isSlidingIn? 'slide-in' : ''} ${isPaused? 'paused' : ''} ${isScaling? 'scale' : ''} ${isRotating? 'rotate' : ''}`}
      />
    </div>
  );
};

export default AnimationComponent;

CSS代码(styles.css)

.animated-element {
  width: 100px;
  height: 100px;
  background-color: blue;
}

@keyframes slide-in {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0);
  }
}

@keyframes scale {
  from {
    transform: scale(1);
  }
  to {
    transform: scale(1.5);
  }
}

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.slide-in {
  animation: slide-in 1s forwards;
}

.paused {
  animation-play-state: paused;
}

.scale {
  animation: scale 1s forwards;
}

.rotate {
  animation: rotate 2s forwards;
}