首页 > 解决方案 > 为什么 cancelAnimationFrame () 不会在 MouseDown 事件上停止动画?

问题描述

为什么cancelAnimationFrame ()不会在MouseDown 事件上停止动画?但是第二次点击会触发动画停止。可能是什么问题呢?有没有办法在过早停止动画之后从“动画函数”返回当前的“ cur ”和“ rez ”值?

完整版的代码。 https://codesandbox.io/s/peaceful-silence-bm6hx?file=/src/scroll.js

const Scrollable = (props) => {
  const items = props.items;

  let ref = useRef();
  let refAnimation = useRef();

  const [state, setState] = useState({
    isScrolling: false,
    clientX: 0, //Position of the mouse on the object
    scrollX: 0 //Position of the propelled object
  });
  const [touchStart, setTouchStart] = useState(0);

  const onMouseDown = (e) => {
    if (ref && ref.current && !ref.current.contains(e.target)) {
      return;
    }
    e.preventDefault();
    ///////////////-----------------////////////////
    cancelAnimationFrame(refAnimation.current);
    //////////////------------------///////////////
  };

  /////////Mouse Move Event///////////
  const onMouseMove = (e) => {
    if (ref && ref.current && !ref.current.contains(e.target)) {
      return;
    }
    e.preventDefault();
    

    if (isScrolling === true) {
      let sX = scrollX - e.clientX + clientX;
      let cX = e.clientX;


        ref.current.scrollLeft = scrollX - e.clientX + clientX;
        setState({
          ...state,
          scrollX: sX,
          clientX: cX
        });
    }
  };

  /////Mouse UP Event/////
  const onMouseUp = (e) => {
    if (ref && ref.current && !ref.current.contains(e.target)) {
      return;
    }
    e.preventDefault();

    let touchShift = touchStart - state.clientX;
    let rez;
    let shift;


    if (touchShift < 0) {
      shift = 300 + touchShift;
      rez = state.scrollX - shift;
      let speed = shift / 400;
      let cur = state.scrollX;

      if (rez <= -300) {
        setState({
          ...state,
          isScrolling: false
        });
      } else {
        refAnimation.current = requestAnimationFrame(() =>
          animate(cur, speed, rez, "left")
        );
      }
    }

    if (touchShift > 0) {
      ...
    }

    if (touchShift === 0) {
      setState({
        ...state,
        isScrolling: false
      });
    }
  };

  //////A callable function that should do the animation
  const animate = (cur, speed, rez, dir = "left", callback) => {
    refAnimation.current = requestAnimationFrame(() =>
      animate(cur, speed, rez, dir)
    );
    cur = dir === "left" ? cur - speed : cur + speed;
    ref.current.scrollLeft = cur.toFixed(2);
    
    if (Math.round(cur) === rez) {
      cancelAnimationFrame(refAnimation.current);
      setState({
        ...state,
        scrollX: rez,
        isScrolling: false
      });
    }
  };

  /////////////////////////////////////////

  useEffect(() => {
    document.addEventListener("mousedown", onMouseDown);
    document.addEventListener("mouseup", onMouseUp);
    document.addEventListener("mousemove", onMouseMove);
    return () => {
      document.removeEventListener("mousedown", onMouseDown);
      document.removeEventListener("mouseup", onMouseUp);
      document.removeEventListener("mousemove", onMouseMove);
    };
  });
  useEffect(() => {
    if (ref.current === true) {
      refAnimation.current = requestAnimationFrame(() => animate(0, 0, 0));
    }
    return () => {
      cancelAnimationFrame(refAnimation.current);
    };
  }, []);


  return (
    <div className={classes.charPage}>
      <div
        className={classes.items}
        ref={ref}
        onMouseDown={onMouseDown}
        onMouseUp={onMouseUp}
        onMouseMove={onMouseMove}
      >
      </div>
    </div>
  );
};

标签: javascriptreactjsanimationrequestanimationframecancelanimationframe

解决方案


在附加了动画的事件中,在再次调用动画之前,必须先使用函数--> cancelAnimationFrame(refAnimation.current)清除旧的

   else {      

cancelAnimationFrame(refAnimation.current)

    refAnimation.current = requestAnimationFrame(() =>
      animate(cur, speed, rez, "left")
    );

推荐阅读