问题描述
我正在使用 Framer Motion 在 React 中制作汉堡菜单动画。当我点击汉堡菜单时,侧抽屉和导航项从左侧滑入。
当我点击关闭菜单图标时,整个侧边抽屉向左滑出(这意味着 SideDrawer 组件上的退出道具正在工作)。
我想要什么? 当我单击关闭图标时,我希望导航项先滑出,然后滑出侧抽屉。我曾尝试向儿童导航项添加退出道具。但它不起作用。
怎样才能达到想要的效果?
代码片段如下:
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",};
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 },};
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;
解决方法
你需要告诉 side drawer 等到孩子们的退出动画结束,然后再开始自己的退出动画。
您可以使用 when
的 transition
属性执行此操作。请参阅文档中的 Orchestration。
在您的情况下,您可以将它添加到您的 initial
的 drawerVariants
变体中,因为这是您在退出时动画化的变体:
initial: {
x: "-100vw",opacity: 0,transition: {
when: "afterChildren"
}
},
如果你想反映动画in行为,你可能还想在那里添加一些惊人的和缓和的效果,但我会留给你。