【问题标题】:Framer Motion (React): How to order initial, exit and layout animations?Framer Motion (React):如何排序初始、退出和布局动画?
【发布时间】:2021-06-30 20:27:03
【问题描述】:

我正在使用 framer-motion 对网格列的变化进行动画处理。

这是我想做的:

  1. 我在一个网格中有九个按钮(#db-wrapper 是网格容器)。

  1. 用户切换到“最大化”视图(props.minimize 更改) 第四列被添加到网格中,已经存在的按钮移动到新位置,为其余按钮留下空白单元格。然后,新按钮从底部滑入,填充空单元格。网格中的按钮现在位于连续的单元格中。

  1. 现在用户切换回最小化视图。首先,所有将被删除的按钮都应该滑到底部。
  2. 然后,其余按钮应移至网格中的新位置(它们的旧位置,如开头那样),以便填充连续的单元格。

(基本上,我想在用户切换回来后向后执行第 1 步和第 2 步)

我已经完成了第 1 步和第 2 步。这是功能组件:

const DrumButtons = (props) => {
  const drumButtonsVariants = {
    hidden: {
      y: "140vh",
    },
    visible: {
      y: 0,
      transition: {
        type: "tween",
        duration: 1,
        delay: 0.1,
      },
    },
    exit: {
      y: "140vh",
      transition: {
        type: "tween",
        duration: 1,
        delay: 0.1,
      },
    },
  };

  let dbWrapperStyle = {};
  if (!props.minimized) {
    dbWrapperStyle = {
      gridTemplateColumns: "1fr 1fr 1fr 1fr",
    };
  }

  let singleWrapperStyle = {
    width: "100%",
    height: "100%",
  };
  let buttonTransition = { duration: 0.5, delay: 0.1 };
  return (
    <div id="db-wrapper" style={dbWrapperStyle}>
      <AnimatePresence>
        {props.buttonsarr.map((elem, i) => {
          return (
            <motion.div
              variants={drumButtonsVariants}
              initial="hidden"
              animate="visible"
              exit="exit"
              key={elem.press}
              style={singleWrapperStyle}
            >
              <motion.button
                layout
                transition={buttonTransition}
                key={elem.press}
                className="drum-pad"
                onClick={dbHandleClickWrapper(
                  props.changetext,
                  props.buttonsarr
                )}
                id={elem.name}
              >
                <span className="front">{elem.press.toUpperCase()}</span>
                <audio
                  key={elem.press.toUpperCase()}
                  id={elem.press.toUpperCase()}
                  src={props.buttonsarr[i].source}
                  preload="auto"
                  className="clip"
                ></audio>
              </motion.button>
            </motion.div>
          );
        })}
      </AnimatePresence>
    </div>
  );
};

到底是什么问题?

以下是当前从“最大化”切换回“最小化”时发生的情况:

  1. 不再需要的按钮滑到底部。同时,4 个网格列减少为 3 个列。因此,剩余的按钮会滑动到它们在 3 列宽的网格中的位置,为当前滑出但仍存在于 DOM 中的按钮留下空白单元格。
  2. 移除其他按钮后,其余按钮会再次移动以填充网格的连续单元格。

这是我尝试过的:

  1. 我尝试将when: "beforeChildren" 添加到drumButtonsVariants 的转换中。没有任何改变。
  2. 我曾尝试过延迟,但从未达到预期的结果。如果我延迟布局动画,从 DOM 中移除按钮也会延迟,从而导致相同的不良结果。

你可以在这里查看我的完整代码:

(主分支)https://github.com/Julian-Sz/FCC-Drum-Machine/tree/main

(有问题的版本)https://github.com/Julian-Sz/FCC-Drum-Machine/tree/284606cac7cbc4bc6e13bf432c563eab4814d370

请随意复制和分叉此存储库!

【问题讨论】:

    标签: javascript reactjs animation framer-motion


    【解决方案1】:

    诀窍是对dbWrapperStyle 使用状态。 那么AnimatePresenceonExitComplete就可以使用了。

    当用户再次切换到最小化时会发生这种情况:

    1. 已移除的按钮滑出(但它们仍在 DOM 中 - 占据网格单元格)
    2. 现在它们从 DOM 中移除,onExitComplete 触发:网格列变为 3 列并且组件被重新渲染。从 DOM 中移除和网格更改是相继发生的(没有任何延迟) - 产生流畅的动画!

    这是新组件:

    const DrumButtons = (props) => {
      const drumButtonsVariants = {
        visible: {
          y: 0,
          transition: {
            type: "tween",
            duration: 0.8,
            delay: 0.1,
          },
        },
        exit: {
          y: "140vh",
          transition: {
            type: "tween",
            duration: 0.8,
            delay: 0.1,
          },
        },
      };
    
      // BEFORE------------
      // let dbWrapperStyle = {};
      // if (!props.minimized) {
      //   dbWrapperStyle = {
      //     gridTemplateColumns: "1fr 1fr 1fr 1fr",
      //   };
      // }
    
      // AFTER-------------
      const [dbWrapperStyle, setWrapperStyle] = useState({});
      useEffect(() => {
        if (!props.minimized) {
          setWrapperStyle({ gridTemplateColumns: "1fr 1fr 1fr 1fr" });
        }
      }, [props.minimized]);
    
      let singleWrapperStyle = {
        width: "100%",
        height: "100%",
      };
    
      let buttonTransition = {
        type: "spring",
        duration: 0.9,
        delay: 0.1,
        bounce: 0.5,
      };
    
      return (
        <div id="db-wrapper" style={dbWrapperStyle}>
          <AnimatePresence
            onExitComplete={() => {
              setWrapperStyle({ gridTemplateColumns: "1fr 1fr 1fr" });
            }}
          >
            {props.buttonsarr.map((elem, i) => {
              return (
                <motion.div
                  variants={drumButtonsVariants}
                  initial="exit"
                  animate="visible"
                  exit="exit"
                  key={elem.press}
                  style={singleWrapperStyle}
                >
                  <motion.button
                    layout
                    transition={buttonTransition}
                    key={elem.press}
                    className="drum-pad"
                    onClick={dbHandleClickWrapper(
                      props.changetext,
                      props.buttonsarr
                    )}
                    id={elem.name}
                  >
                    <span className="front">{elem.press.toUpperCase()}</span>
                    <audio
                      key={elem.press.toUpperCase()}
                      id={elem.press.toUpperCase()}
                      src={props.buttonsarr[i].source}
                      preload="auto"
                      className="clip"
                    ></audio>
                  </motion.button>
                </motion.div>
              );
            })}
          </AnimatePresence>
        </div>
      );
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-02-13
      • 2022-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-16
      • 2020-12-28
      相关资源
      最近更新 更多