首页 > 解决方案 > 使用 React 的动态 CSS 动画变量

问题描述

const {useState, useEffect, useRef} = React;
const App = () => {
  const [pressed, setPressed] = useState(false);
  const [shoot, setShoot] = useState(false);
  const [seconds, setSeconds] = useState(0);
  useInterval(() => {
    // Your custom logic here
    pressed && seconds < 3 && setSeconds((prev)=> Number((prev+0.1).toFixed(1)));
  }, 100);
  
  useInterval(()=>{
    !pressed && seconds > 0 && setSeconds((prev)=>{
      if( Number((prev-0.5).toFixed(1)) < 0){
        return 0;
      }
      return Number((prev-0.5).toFixed(1))
    });
  }, 20)
  return (
    <div>
      <button
        onMouseDown={()=>{
          console.log('mouseDown')
          setShoot(false);
          setPressed(true);
        }}
        onMouseUp={()=>{
          console.log('mouseUp')
          setShoot(true);
          setPressed(false);
        }}
        style={{
          transform: `rotate(-${seconds*15}deg)`
        }}
      >Press</button>
      <span className={`dot ${shoot ? '--shooted' : ''}`} />
      <p>{seconds}</p>
    </div>
  )
};
ReactDOM.render(<App />, document.getElementById('root'));

function useInterval(callback, delay) {
  const savedCallback = useRef();

  // Remember the latest callback.
  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  // Set up the interval.
  useEffect(() => {
    function tick() {
      savedCallback.current();
    }
    if (delay !== null) {
      let id = setInterval(tick, delay);
      return () => clearInterval(id);
    }
  }, [delay]);
}
.dot{
  position: absolute;
  width: 16px;
  height: 16px;
  border-radius:100%;
  background: red;
}

.dot.--shooted{
  animation: test 1s;
}

@keyframes test{
  0%{
    transform: translateX(0px);
  }
  100%{
    transform: translateX(200px); // it should be dynamic px.
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.26.0/moment.min.js"></script>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root" />

我想在按下按钮的几秒钟内移动红点。

但我正在使用animation,所以我无法控制pxCSS 中的。

如果我按下按钮 3 秒,红点应该移动到300px.

如果我按下按钮 1 秒,红点应该移动到100px.

标签: javascriptcssreactjs

解决方案


这是一个例子。但是您需要添加一个逻辑才能将其移回。

const {
  useState,
  useEffect,
  useRef
} = React;
const App = () => {
  const [pressed, setPressed] = useState(false);
  const [shoot, setShoot] = useState(false);
  const [seconds, setSeconds] = useState(0);
  const dotRef = useRef();

  useInterval(() => {
    // Your custom logic here
    pressed && seconds < 3 && setSeconds((prev) => Number((prev + 0.1).toFixed(1)));
  }, 100);

  useInterval(() => {
    !pressed && seconds > 0 && setSeconds((prev) => {
      if (Number((prev - 0.5).toFixed(1)) < 0) {
        return 0;
      }
      return Number((prev - 0.5).toFixed(1))
    });
  }, 20)

  const handleMouseUp = () => {
    dotRef.current.style.transform = `translateX(${seconds * 100}px)`;
  }

  return ( <
    div >
    <
    button onMouseDown = {
      () => {
        console.log('mouseDown')
        setShoot(false);
        setPressed(true);
      }
    }
    onMouseUp = {
      () => {
        console.log('mouseUp')
        setShoot(true);
        setPressed(false);
        handleMouseUp();
      }
    }
    style = {
      {
        transform: `rotate(-${seconds*15}deg)`
      }
    } >
    Press < /button> <
    span className = {
      `dot ${shoot ? '--shooted' : ''}`
    }
    ref = {
      dotRef
    }
    /> <
    p > {
      seconds
    } < /p> < /
    div >
  )
};
ReactDOM.render( < App / > , document.getElementById('root'));

function useInterval(callback, delay) {
  const savedCallback = useRef();

  // Remember the latest callback.
  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  // Set up the interval.
  useEffect(() => {
    function tick() {
      savedCallback.current();
    }
    if (delay !== null) {
      let id = setInterval(tick, delay);
      return () => clearInterval(id);
    }
  }, [delay]);
}
.dot {
  position: absolute;
  width: 16px;
  height: 16px;
  border-radius: 100%;
  background: red;
  transition: transform 1s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.26.0/moment.min.js"></script>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root" />


推荐阅读