Next.js中Framer Motion首次折叠动画卡顿问题
解决Next.js中Framer Motion折叠动画首次卡顿问题
问题原因
首次切换时使用height: 'auto',Framer Motion需要临时计算元素的实际高度,这个过程会触发DOM重排,导致动画卡顿。后续操作时高度已被缓存,所以恢复流畅。
修复方案
方案1:用动态计算的元素高度替代height: 'auto'
通过useRef获取元素,在动画开始前计算其scrollHeight,将具体数值作为动画目标高度:
import { useRef, useState, useLayoutEffect } from 'react'; import { AnimatePresence, motion } from 'framer-motion'; // 组件内部逻辑 const contentRef = useRef(null); const [contentHeight, setContentHeight] = useState(0); useLayoutEffect(() => { if (contentRef.current) { setContentHeight(contentRef.current.scrollHeight); } }, [data.content]); // 渲染代码 <AnimatePresence> {isOpen && ( <motion.div ref={contentRef} className={styles.content} key="content" initial={{ opacity: 0, height: 0 }} animate={{ opacity: 1, height: contentHeight }} exit={{ opacity: 0, height: 0 }} transition={{ duration: 0.3 }} style={{ overflow: 'hidden' }} > {data.content} </motion.div> )} </AnimatePresence>
方案2:使用Framer Motion的layout属性
layout属性会让Framer Motion自动跟踪元素尺寸变化,避免手动设置height: 'auto'带来的计算开销:
<AnimatePresence> {isOpen && ( <motion.div className={styles.content} key="content" initial={{ opacity: 0, height: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0, height: 0 }} layout style={{ overflow: 'hidden' }} > {data.content} </motion.div> )} </AnimatePresence>
方案3:预计算固定内容的高度
如果data.content是固定不变的,可以提前计算好高度值,直接用具体数值替代auto,彻底避免动态计算:
// 假设预计算的内容高度为240px <motion.div className={styles.content} key="content" initial="collapsed" animate="open" exit="collapsed" variants={{ open: { opacity: 1, height: '240px' }, collapsed: { opacity: 0, height: 0 }, exit: { opacity: 0, height: 0 }, }} > {data.content} </motion.div>
额外优化提示
- 给
styles.content添加overflow: hidden,避免动画过程中内容溢出 - 调整
transition参数(比如duration、ease),让动画过渡更顺滑
内容的提问来源于stack exchange,提问作者Zura Jeladze
相关产品推荐
相关产品推荐

