如何反向运行 react-spring 动画?

Posted

技术标签:

【中文标题】如何反向运行 react-spring 动画?【英文标题】:How can I run a react-spring animation in reverse? 【发布时间】:2021-09-12 06:08:00 【问题描述】:

我有一个动画,可以很好地从右侧和左侧移动项目。当点击后退按钮时,我想做相反的事情,类似于从移动应用程序的导航堆栈中弹出一个视图。我的代码在下面,单击按钮时如何使动画向后运行?我正在使用 React 17.0.2 和 react-spring 9.2.3 。

import React,  useState, useCallback, CSSProperties, useEffect  from "react";
import 
  useTransition,
  animated,
  AnimatedProps,
  useSpringRef,
 from "react-spring";

import styles from "../styles/components/carousel.module.css";

const Carousel: React.FC = () => 
  const [index, set] = useState(0);
  const onClick = useCallback(() => set((state) => (state + 1) % 6), []);
  const transRef = useSpringRef();
  const transitions = useTransition(index, 
    ref: transRef,
    keys: null,
    from:  opacity: 0, transform: "translate3d(100%,0,0)" ,
    enter:  opacity: 1, transform: "translate3d(0%,0,0)" ,
    leave:  opacity: 0, transform: "translate3d(-50%,0,0)" ,
  );

  useEffect(() => 
    transRef.start();
  , [index, transRef]);

  const pageContent:  text: string; color: string [] = [
     text: "one", color: "lightpink" ,
     text: "two", color: "lightblue" ,
     text: "three", color: "lightgreen" ,
  ];

  const pages: ((
    props: AnimatedProps< style: CSSProperties >
  ) => React.ReactElement)[] = pageContent.map((obj) => 
    return function createAnimatedDiv( style ) 
      return (
        <animated.div style= ...style, background: obj.color >
          obj.text
        </animated.div>
      );
    ;
  );

  const onBackClicked = useCallback(() => set((state) => (state - 1) % 6), []);

  return (
    <>
      <button onClick=onBackClicked>Back</button>
      <div className=`flex fill $styles.container` onClick=onClick>
        transitions((style, i) => 
          const Page = pages[i];
          return <Page style=style />;
        )
      </div>
    </>
  );
;

export default Carousel;

【问题讨论】:

为此类问题准备codesandbox 会很高兴。 【参考方案1】:

首先你需要知道动画的方向。为此,您可以使用usePrevious 挂钩并比较当前和以前的索引。然后,根据方向,您可以返回不同的过渡配置。

type Direction = 'left' | 'right' | null;

// helpers

const getDirection = (index: number, previousIndex: number): Direction => 
  if (index === number) 
    return null;
  

  return index > previousIndex ? 'right' : 'left';
;

const getTransitionConfig = (direction: Direction): Parameters<typeof useTransition>[1] => 
  if (direction === 'right') 
    return 
      from:  opacity: 0, left: -300 ,
      enter:  opacity: 1, left: 0 ,
      leave:  opacity: 0, left: 300 ,
    ;
  

  if (direction === 'left') 
    return 
      from:  opacity: 0, left: 300 ,
      enter:  opacity: 1, left: 0 ,
      leave:  opacity: 0, left: -300 ,
    ;
  

  return ;
;

// component

const [index, set] = useState(0);
const previousIndex = usePrevious(index);
const animationDirection = getDirection(index, previousIndex);

const transitionConfig = useMemo(() => (
  ref: transRef,
  keys: null,
  ...getTransitionConfig(animationDirection)
), [animationDirection, getTransitionConfig]);

const transitions = useTransition(index, transitionConfig);
// ...

为了简单起见,我使用了left 属性。当然,你可以使用transform

【讨论】:

以上是关于如何反向运行 react-spring 动画?的主要内容,如果未能解决你的问题,请参考以下文章

React-Spring - 改变过渡动画速度

react-spring 中的“动画”做啥?

React JS:如何在 react-spring 中使用响应式样式

使用 React-spring useTransition 的动画在递归循环中无法按预期工作

如何让你的Android Lottie动画反向播放

如何在 Adob​​e Animate 中悬停时反向播放动画?