【问题标题】:continuous motion of react card animation反应卡动画的连续运动
【发布时间】:2021-08-20 02:38:18
【问题描述】:

按○按钮后向右滑动。当您按下✖️按钮时,有一张卡片可以向左滑动。
如果在按○键后立即按✖️键,卡片向右滑动后会返回左侧。
我想让它一旦按下按钮,如果是○,卡片就会向右移动,如果是✖️,则向左移动。

import React, { FunctionComponent, useState } from "react";
import {
  animate,
  useAnimation,
  useMotionValue,
  useTransform,
  MotionValue,
  motion
} from "framer-motion";

interface Props {
  animate?: { x: number; y: number };
  style: {
    x?: MotionValue;
    y?: MotionValue;
    zIndex: number;
    rotate?: MotionValue;
  };
  card: { text: string; background: string };
}

const SwipeBox: React.FunctionComponent<Props> = (props) => {
  return (
    <motion.div
      animate={props.animate}
      className="card"
      style={{
        ...props.style,
        background: "white",
        borderRadius: "8px",
        display: "grid",
        top: 0,
        left: 0,
        placeItems: "center center",
        position: "absolute",
        width: "100%"
      }}
      transition={{ duration: 1 }}
    >
      {props.children}
    </motion.div>
  );
};

const App: FunctionComponent = () => {
  const controls = useAnimation();
  console.log(controls);
  const [cards, setCards] = useState([
    { text: "Up or down", background: "red" },
    { text: "Left or right", background: "green" },
    { text: "Swipe me!", background: "gray" },
    { text: "Swipe me!", background: "purple" },
    { text: "Swipe me!", background: "yellow" }
  ]);

  const x = useMotionValue(0);
  const y = useMotionValue(0);

  const animateCardSwipe = (animation: { x: number; y: number }) => {
    animate(x, animation.x, {
      duration: 1,
      onComplete: () => {
        x.set(0);
        y.set(0);
        setCards([...cards.slice(0, cards.length - 1)]);
      }
    });
  };

  const [anime, setAnime] = useState<{ animation: { x: number; y: number } }>({
    animation: { x: 0, y: 0 }
  });

  const rotate = useTransform(x, [-950, 950], [-30, 30]);

  const onClickLeft = () => {
    animateCardSwipe({ x: 1400, y: 0 });
  };

  const onClickRight = () => {
    animateCardSwipe({ x: -1400, y: 0 });
  };

  return (
    <div style={{ display: "flex", flexDirection: "column" }}>
      <div>
        {cards.map((card, index) =>
          index === cards.length - 1 ? (
            <SwipeBox
              animate={anime.animation}
              card={card}
              key={index}
              style={{ x, y, zIndex: index, rotate: rotate }}
            >
              <div
                style={{
                  width: "400px",
                  height: "300px",
                  background: `${card.background}`
                }}
              >
                {card.text}
              </div>
            </SwipeBox>
          ) : (
            <SwipeBox
              card={card}
              key={index}
              style={{
                zIndex: index
              }}
            >
              <div
                style={{
                  width: "400px",
                  height: "300px",
                  background: `${card.background}`
                }}
              >
                {card.text}
              </div>
            </SwipeBox>
          )
        )}
      </div>
      <div style={{ zIndex: 999 }}>
        <button onClick={onClickRight}>✖️</button>
        <button onClick={onClickLeft}>○</button>
      </div>
    </div>
  );
};

export default App;

【问题讨论】:

    标签: reactjs framer-motion


    【解决方案1】:

    问题是animate 被多次调用,翻译值不同。它尝试将卡片转换为指定的 x 值。

    我认为最简单的解决方案是在制作动画时禁用按钮。

    为此,您可以创建一些状态:

    const [isAnimating, setIsAnimating] = useState(false);
    

    并使用此状态有条件地禁用您的按钮:

    <button disabled={isAnimating} onClick={onClickRight}>
        ✖️
    </button>
    <button disabled={isAnimating} onClick={onClickLeft}>
        ○
    </button>
    

    然后你可以像这样调整你的animateCardSwipe函数:

    const animateCardSwipe = (animation: { x: number, y: number }) => {
      setIsAnimating(true);
      animate(x, animation.x, {
        duration: 1,
        onComplete: () => {
          x.set(0);
          y.set(0);
          setCards([...cards.slice(0, cards.length - 1)]);
          setIsAnimating(false);
        },
      });
    };
    

    如果开始滑动动画,则应禁用按钮并将isAnimating 设置为true。如果滑动动画完成,则应启用按钮并将isAnimating 设置为false。

    使用按钮的disabled 属性还可以让用户清楚地知道,当动画已经开始时按下按钮是无效的。

    Sandbox Demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多