退出无法在Framer Motion中运行的子项的动画 [英] Exit animation for children items not working in Framer Motion

查看:129
本文介绍了退出无法在Framer Motion中运行的子项的动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Framer Motion在React中制作汉堡菜单动画.当我单击汉堡菜单时,侧面抽屉和导航项目从左侧滑入.

I am making a hamburger menu animation in React using Framer Motion. When I click on the hamburger menu, the side drawer and the navigation items slide in from the left.

当我单击关闭菜单图标时,整个侧抽屉就会向左滑动(这意味着SideDrawer组件上的退出道具正在工作).

When I click on the close menu icon, then the whole side drawer slides out to the left(which means the exit prop on SideDrawer component is working).

我想要什么?当我单击关闭图标时,我希望导航项先滑出,然后再滑出侧抽屉.我尝试将退出道具添加到儿童导航项中.但这是行不通的.

What do I want? When I click on the close icon, I want the navigation items to slide out first and then the side drawer. I have tried adding exit prop to children navigation items. But it does not work.

我如何达到预期的效果?

How can I achieve the desired effect?

代码段如下:

src/App.js

import React, { useState } from "react";
import "./App.css";
import Menu from "./components/Menu";
import SideDrawer from "./components/SideDrawer";
import Overlay from "./components/Overlay";

const App = () => {
  const [menuOpen, setMenuOpen] = useState(false);
  const handleMenuClick = () => {
    setMenuOpen(!menuOpen);
  };

  return (
    <div className="App">
      <Menu menuOpen={menuOpen} onMenuClick={handleMenuClick} />
      <SideDrawer menuOpen={menuOpen} />
      <Overlay menuOpen={menuOpen} />
    </div>
  );
};

export default App;

src/components/Menu.js

import React, { useState } from "react";
import { motion } from "framer-motion";

const lineOneVariants = {
  initial: { rotate: "0deg" },
  animate: { y: ".8rem", rotate: "45deg", transformOrigin: "center center" },
};
const lineTwoVariants = {
  initial: { opacity: 1 },
  animate: { opacity: 0 },
};
const lineThreeVariants = {
  initial: { rotate: "0deg" },
  animate: { y: "-.8rem", rotate: "-45deg", transformOrigin: "center center" },
};

const Menu = ({ onMenuClick, menuOpen }) => {
  return (
    <div className="hamburger_menu">
      <div className="hamburger_menu-line-container" onClick={onMenuClick}>
        <motion.div
          variants={lineOneVariants}
          initial="initial"
          animate={menuOpen ? "animate" : "initial"}
          className="hamburger_menu-line-1"
        ></motion.div>
        <motion.div
          variants={lineTwoVariants}
          initial="initial"
          animate={menuOpen ? "animate" : "initial"}
          className="hamburger_menu-line-2"
        ></motion.div>
        <motion.div
          variants={lineThreeVariants}
          initial="initial"
          animate={menuOpen ? "animate" : "initial"}
          className="hamburger_menu-line-3"
        ></motion.div>
      </div>
    </div>
  );
};

export default Menu;

src/components/Overlay.js

import React from "react";
import { motion } from "framer-motion";

const overlayVariants = {
  initial: { opacity: 0 },
  animate: { opacity: 1 },
};

const Overlay = ({ menuOpen }) => {
  return (
    <motion.div
      variants={overlayVariants}
      initial="initial"
      animate={menuOpen ? "animate" : "initial"}
      className="overlay"
    ></motion.div>
  );
};

export default Overlay;

src/components/SideDrawer.js

import React from "react";
import { motion, AnimatePresence } from "framer-motion";

const drawerVariants = {
  initial: {
    x: "-100vw",
    opacity: 0,
  },
  animate: {
    x: 0,
    opacity: 1,
    transition: {
      type: "linear",
      ease: "easeInOut",
      staggerChildren: 0.1,
      delayChildren: 0.15,
    },
  },
};

const drawerMenuVariants = {
  initial: { x: "-5rem", opacity: 0 },
  animate: {
    x: 0,
    opacity: 1,
    transition: {
      type: "linear",
      ease: "easeInOut",
    },
  },
};

const SideDrawer = ({ menuOpen }) => {
  return (
    <AnimatePresence>
      {menuOpen && (
        <motion.div
          variants={drawerVariants}
          initial="initial"
          animate="animate"
          exit="initial"
          className="sideDrawer"
        >
          <nav className="sideDrawer-menu">
            <ul>
              <motion.li
                variants={drawerMenuVariants}
                whileHover={{ scale: 1.05 }}
              >
                <a href="#">Register/Login</a>
              </motion.li>
              <motion.li
                variants={drawerMenuVariants}
                whileHover={{ scale: 1.05 }}
              >
                <a href="#">About</a>
              </motion.li>
              <motion.li
                variants={drawerMenuVariants}
                whileHover={{ scale: 1.05 }}
              >
                <a href="#">Projects</a>
              </motion.li>
              <motion.li
                variants={drawerMenuVariants}
                whileHover={{ scale: 1.05 }}
              >
                <a href="#">CV</a>
              </motion.li>
            </ul>
          </nav>
        </motion.div>
      )}
    </AnimatePresence>
  );
};

export default SideDrawer;

推荐答案

您需要让侧面抽屉等到孩子的退出动画结束后再开始自己的退出动画.

You need to tell the side drawer to wait until the exit animation for the children finishes before starting its own exit animation.

您可以使用 transition when 属性来执行此操作.请参阅文档中的编排.

You can do this by using the when property of the transition. See Orchestration in the docs.

在您的情况下,请将其添加到 drawerVariants initial 变体中,因为这是您在退出时动画的变体:

In your case, you'd add it to the initial variant of your drawerVariants, since that's the variant you animate to on exit:

initial: {
  x: "-100vw",
  opacity: 0,
  transition: {
    when: "afterChildren"
  }
},

如果要镜像动画 in 的行为,您可能还想在其中添加一些交错和缓和的地方,但我将留给您自己.

You probably also want to add some staggering and easing there if you want to mirror the animate in behavior, but I'll leave that up to you.

这篇关于退出无法在Framer Motion中运行的子项的动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆