React Accordion组件用AnimatePresence关闭时卡顿的原因与修复
解决Accordion组件关闭时动画卡顿问题
你的问题出在**fit-content作为height动画目标+Spring过渡曲线的组合**上:Spring的弹性特性会让高度计算在接近0时出现精度偏差,加上fit-content是动态计算值,framer-motion反向过渡时无法精准插值到0,最终导致最后阶段内容突然跳变收起。
下面是两种可行的修复方案:
方案1:改用scaleY动画(推荐,更稳定)
放弃height动画,用scaleY配合transformOrigin: top实现展开收起,完全避开动态高度计算的问题:
import React, { useState } from "react"; import { motion, AnimatePresence } from "framer-motion"; import Arrow from "/FAQ_Arrow.svg"; export default function Accordion({ header, text }) { const [isOpen, toggleOpen] = useState(false); return ( <div className="w-full border-2 border-gray-700 rounded-t-md rounded-md py-4 px-8 bg-white text-black"> <button className="flex justify-between items-center w-full" onClick={() => toggleOpen(!isOpen)} > <h1 className="text-large md:text-2xl font-bold text-[#6130C9]">{header}</h1> <img src={Arrow} alt="展开/收起箭头" className={`transition-all duration-300 ${ isOpen ? "-rotate-180" : "" }`} /> </button> <AnimatePresence mode="sync"> {isOpen && ( <motion.div initial={{ scaleY: 0, opacity: 0 }} animate={{ scaleY: 1, opacity: 1 }} exit={{ scaleY: 0, opacity: 0 }} transition={{ duration: 0.3, ease: "easeInOut" }} style={{ transformOrigin: "top center" }} className="text-base mt-4 overflow-hidden" > <h3>{text}</h3> </motion.div> )} </AnimatePresence> </div> ); }
方案2:调整height动画的过渡曲线与目标值
如果坚持用height动画,把fit-content换成auto,同时将Spring过渡改为平缓的easeInOut曲线,避免弹性导致的计算偏差:
// 仅修改motion.div部分,其余代码不变 <motion.div initial={{ height: 0 }} animate={{ height: "auto" }} exit={{ height: 0 }} transition={{ duration: 0.3, ease: "easeInOut" }} className="text-base mt-4 overflow-hidden" > <h3>{text}</h3> </motion.div>
关键说明
- Spring过渡适合位置、缩放这类需要弹性效果的场景,但不适合高度这类需要精准插值到0的动画,平缓的ease曲线更适配折叠面板的收起逻辑。
scaleY动画基于transform实现,无需计算内容高度,性能和流畅度更优,是折叠面板动画的常用方案。
内容的提问来源于stack exchange,提问作者Recaptchow
相关产品推荐
相关产品推荐

