我想在按下按钮时减慢 Box 的动画

时间:2021-08-02 01:10:00

标签: reactjs typescript framer-motion chakra-ui

我正在使用 react.js、Typescript、chakra 和动画框架。 有一个 MotionSwipe 组件,可让您向右和向左滑动。可以拖动它来滑动子元素的 Box。 我们希望 Box 不仅可以通过拖动来向右或向左移动,还可以通过按下按钮来向右或向左移动。 在按下按钮时调用的 onClickSwipe 函数中,我执行了 animateCardSwipe 函数使其向右滑动。但是,动画太快了,我看不到。我想减慢按下按钮时 Box 向右移动的动画。

import { Button,Box  } from '@chakra-ui/react';
import { PanInfo, useMotionValue, useTransform } from 'framer-motion';
import { NextPage } from 'next';
import { MotionSwipe } from 'components/MotionSwipe';
import React, { useState } from 'react';

const Component: React.VoidFunctionComponent = () => {
  const [cards, setCards] = useState([
    { text: 'Up or down', background: 'red' },
    { text: 'Left or right', background: 'green' },
    { text: 'Swipe me!', background: 'gray' },
  ]);

  const [dragStart, setDragStart] = useState<{ axis: string | null; animation: { x: number; y: number } }>({
    axis: null,
    animation: { x: 0, y: 0 },
  });

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

  const onDirectionLock = (axis: string | null) => setDragStart({ ...dragStart, axis: axis });

  const animateCardSwipe = (animation: { x: number; y: number }) => {
    setDragStart({ ...dragStart, animation });

    setTimeout(() => {
      setDragStart({ axis: null, animation: { x: 0, y: 0 } });
      x.set(0);
      y.set(0);
      setCards([...cards.slice(0, cards.length - 1)]);
    }, 200);
  };

  const onDragEnd = (info: PanInfo) => {
    if (dragStart.axis === 'x') {
      if (info.offset.x >= 400) animateCardSwipe({ x: 300, y: 0 });
      else if (info.offset.x <= -400) animateCardSwipe({ x: -300, y: 0 });
    } else {
      if (info.offset.y >= 100) animateCardSwipe({ x: 0, y: 100 });
      else if (info.offset.y <= -100) animateCardSwipe({ x: 0, y: -100 });
    }
  };

  const rotate = useTransform(x, [-700, 700], [-90, 90]);

  const onClickSwipe = () => {
    animateCardSwipe({ x: 500, y: 0 });
  };

  return (
    <>
      <Box display="flex" justifyContent="center" width="300px">
        {cards.map((card, index) =>
          index === cards.length - 1 ? (
            <MotionSwipe
              animate={dragStart.animation}
              card={card}
              key={index}
              onDirectionLock={(axis: string) => onDirectionLock(axis)}
              onDragEnd={(e: MouseEvent, info: PanInfo) => onDragEnd(info)}
              style={{ x, y, zIndex: index, rotate: rotate }}
            >
              <Box background={card.background} height="300px" width="300px"></Box>
            </MotionSwipe>
          ) : (
            <MotionSwipe
              card={card}
              key={index}
              style={{
                zIndex: index,
              }}
            >
              <Box background={card.background} height="300px" width="300px"></Box>
            </MotionSwipe>
          ),
        )}
      </Box>
      <Button onClick={onClickSwipe}>
        ○
      </Button>
      <Button>✖︎</Button>
    </>
  );
};

const SwipeBox: NextPage = () => {
  return <Component />;
};

export default SwipeBox;

interface Props {
  animate?: { x: number; y: number };
  onDirectionLock?: (axis: 'x' | 'y') => void;
  onDragEnd?: (e: MouseEvent, info: PanInfo) => void;
  style: { x?: MotionValue; y?: MotionValue; zIndex: number; rotate?: MotionValue };
  card: { text: string; background: string };
}

export const MotionSwipe: React.FunctionComponent<Props> = (props) => {
  return (
    <MotionBox
      animate={props.animate}
      background="white"
      borderTopRadius="8px"
      className="card"
      display="grid"
      drag
      dragConstraints={{ left: 0, right: 0, top: 0, bottom: 0 }}
      dragDirectionLock
      left={0}
      onDirectionLock={props.onDirectionLock}
      onDragEnd={props.onDragEnd}
      placeItems="center center"
      position="absolute"
      style={{ ...props.style }}
      top={0}
      transition={{ ease: [0.6, 0.05, -0.01, 0.9], duration: 3 }}
    >
      {props.children}
    </MotionBox>
  );
};

1 个答案:

答案 0 :(得分:0)

是的,速度快的时候没问题。如何更改:

  1. 设置 useState 变量以检查按钮是否被按下。 例如:const [pressed, setPressed] = useState(false);
  2. 如果按钮被按下,则设置 setPressed(true)
  3. 如果 pressed(true),您添加一些 transitionanimation 道具和 duration

如果您没有 duration,您的元素将在按钮点击后立即触发。