【问题标题】:How to run CSS animation again in React?如何在 React 中再次运行 CSS 动画?
【发布时间】:2021-09-18 21:23:37
【问题描述】:

类似的问题还有不少,但我没有找到明确的答案。

有时,我需要在 React 中再次运行 CSS 动画,完成后,在某些条件下。这个案例背后通常有相当复杂的逻辑,所以我对其进行了简化以说明我的意思,而没有额外的复杂性。

假设我有一个复选框来决定是否要运行动画:

当复选框被禁用时,动画会停止,但如果它已经开始,它会结束它的循环。我想知道用 React 重新运行动画(即删除类并再次添加)的正确方法是什么。这是我的组件:

import { useState, useEffect } from 'react';

export default function Spinner() {
  const [isSpinning, setIsSpinning] = useState(true);
  const [isChecked, setIsChecked] = useState(true);

  useEffect(
    () => {
      if (isChecked) {
        setIsSpinning(true);
      }
    },
    [isChecked]
  );

  const spin = () => {
    setIsSpinning(false);

    if (isChecked) {
      // without setTimeout() it doesn't work
      window.setTimeout(() => setIsSpinning(true));
    }
  };

  return (
    <div className="container">
      <input
        type="checkbox"
        checked={isChecked}
        onChange={toggleCheckbox}
      />
      <div
        className={isSpinning && 'spinning'}
        onAnimationEnd={endSpin}
      >
        Hello!
      </div>
    </div>
  );
};

还有 CSS:

@keyframes spinning {
    from {
        transform: rotateX(0);
    }

    to {
        transform: rotateX(360deg);
    }
}

.container {
    display: flex;
    gap: .5em;
}

.spinning {
    animation: spinning 1s;
}

我正在使用window.setTimeout(fn) 在删除后再次添加类名。否则,它会发生在同一个渲染周期中,并且它的行为就像类始终存在一样,因此动画永远不会重新运行。它可以工作,但是在 React 的下一个渲染周期中添加类是否还有另一种不那么 hacky 的方法?

【问题讨论】:

    标签: javascript reactjs css-animations


    【解决方案1】:
    import { useState } from 'react'
    import styled from "styled-components";
    
    const Test = () => {
    
        const [isChecked, setIsChecked] = useState(false);
    
        return (
            <StyledWrapper>
                <div className="container">
                    <input
                        type="checkbox"
                        checked={isChecked}
                        onChange={() => setIsChecked(!isChecked)}
                    />
                    <div
                        className={isChecked ? "spinning" : ""}
                    >
                        Hello!
                    </div>
                </div>
            </StyledWrapper>
        )
    }
    
    export default Test;
    
    const StyledWrapper = styled.div`
    
    .container {
        display: flex;
        gap: .5em;
    }
    
    .spinning {
        animation: spin 1s ease;
        -webkit-animation-name: spin;
        -webkit-animation-duration: 4000ms;
        -webkit-animation-iteration-count: infinite;
        -webkit-animation-timing-function: linear;
        -moz-animation-name: spin;
        -moz-animation-duration: 4000ms;
        -moz-animation-iteration-count: infinite;
        -moz-animation-timing-function: linear;
        -ms-animation-name: spin;
        -ms-animation-duration: 4000ms;
        -ms-animation-iteration-count: infinite;
        -ms-animation-timing-function: linear;
        
        animation-name: spin;
        animation-duration: 4000ms;
        animation-iteration-count: infinite;
        animation-timing-function: linear;
    }
    
    @-moz-keyframes spin {
        from { -moz-transform: rotate(0deg); }
        to { -moz-transform: rotate(360deg); }
    }
    @-webkit-keyframes spin {
        from { -webkit-transform: rotate(0deg); }
        to { -webkit-transform: rotate(360deg); }
    }
    @keyframes spin {
        from {transform:rotate(0deg);}
        to {transform:rotate(360deg);}
    }
    `;
    

    你可以使用这样的东西。 css中有一个叫做animation-iteration-count的属性,可以给定为无穷大。并进一步管理基于复选框单击切换布尔值的状态。现在您可以根据这些布尔值传递 className。

    【讨论】:

      猜你喜欢
      • 2023-01-26
      • 2023-01-22
      • 2020-09-21
      • 1970-01-01
      • 2022-01-20
      • 2015-11-21
      • 2021-04-01
      • 2015-06-25
      • 2013-02-12
      相关资源
      最近更新 更多