React组件挂载/卸载时实现级联交错动画效果问题求解
React 侧边栏交错动画稳定实现方案
用 Framer Motion 原生的变体编排能力即可实现,不需要混用 spring、css transition 等多套方案,核心是通过容器的动画编排参数自动处理子元素时序,完全不需要手动给每个元素写延迟值。
核心实现逻辑
- 侧边栏容器用
AnimatePresence包裹,基于挂载/卸载状态自动触发滑入滑出动画,不需要额外按钮控制 - 容器动画变体配置
staggerChildren参数统一控制子元素交错间隔,通过staggerDirection切换滑入/滑出时的交错顺序:滑入时从上到下正序淡入,滑出时从下到上倒序淡出 - 通过
when参数绑定容器和子元素的动画执行时机,避免容器和内容动画时序错乱
可直接复用的核心代码
import { useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; export default function SidebarDemo() { const [isOpen, setIsOpen] = useState(false); // 侧边栏容器动画配置 const sidebarVariants = { hidden: { x: '100%', transition: { staggerChildren: 0.07, staggerDirection: -1, when: 'afterChildren' } }, visible: { x: 0, transition: { staggerChildren: 0.07, staggerDirection: 1, when: 'beforeChildren' } } }; // 内部标题通用动画配置 const contentVariants = { hidden: { opacity: 0, x: 16 }, visible: { opacity: 1, x: 0 } }; return ( <div className="page"> {/* 触发元素 */} <div className="trigger" onClick={() => setIsOpen(true)}> Information </div> <AnimatePresence> {isOpen && ( <motion.aside className="sidebar" variants={sidebarVariants} initial="hidden" animate="visible" exit="hidden" onClick={() => setIsOpen(false)} > <motion.h1 variants={contentVariants}>主标题</motion.h1> <motion.h3 variants={contentVariants}>二级模块标题</motion.h3> <motion.h5 variants={contentVariants}>辅助说明文本</motion.h5> </motion.aside> )} </AnimatePresence> </div> ); }
关键参数说明:
when: 'beforeChildren':滑入时先执行子元素的交错淡入,再完成容器的位移动画,避免内容提前露在容器外when: 'afterChildren':滑出时等所有子元素完成交错淡出,再执行容器的滑出动画,避免内容还没消失容器就先移走staggerDirection: 1/-1:自动切换子元素动画的触发顺序,不需要单独给滑入滑出写两套子元素延迟配置
之前实现不稳定的常见原因
- 没有用
AnimatePresence包裹条件渲染的侧边栏,导致组件卸载时直接被移除,根本不会执行退出阶段的滑出、淡出动画 - 手动给每个标题写死
transition.delay值,滑入滑出共用同一套延迟,导致滑出时淡出顺序和预期不符 - 没有绑定容器和子元素的动画执行时机,出现容器动画和内容动画互相抢时序的问题
内容的提问来源于stack exchange,提问作者Bruno Arnabar
相关产品推荐
相关产品推荐

