如何在React+Framer Motion中兼顾字符退出动画与容器布局动画?
如何在React+Framer Motion中兼顾字符退出动画与容器布局动画?
嘿,我明白你现在的纠结了——既要让每个字符退出时有丝滑的动画,又要让背景容器跟着文字宽度平滑缩放,这俩需求凑一起确实容易在Framer Motion的结构上踩坑。我之前也遇到过类似的问题,给你捋清楚问题出在哪,以及怎么调整就能解决:
首先,你之前的尝试其实已经摸到门道了,只是AnimatePresence的位置和元素层级的搭配没搞对。咱们先拆解一下核心矛盾:
- AnimatePresence必须直接包裹会被替换的元素(也就是每个单词的容器),才能触发内部元素的exit动画;
- 外层的布局动画容器(带layout的motion.div)必须能监听内部所有元素的尺寸变化,才能平滑过渡宽度。
你之前要么把AnimatePresence包在最外层(导致它只盯着外层容器,看不到里面的单词替换,自然触发不了字符的exit动画),要么把它塞到布局容器里面但用了mode="wait"(导致新旧单词不同时存在,布局容器没法感知尺寸的渐变,只能跳变)。
正确的结构调整方案
直接上能跑的代码,再给你讲每部分的作用:
// 外层是负责背景缩放的布局容器,必须带layout属性 <motion.div layout style={textLoopStyle} transition={transition}> {/* AnimatePresence要直接包裹每个单词的容器,用mode="pop"让新旧元素同时存在 */} <AnimatePresence mode="pop"> {/* 每个单词的容器:加key触发替换,加layout让自身宽度也能平滑过渡 */} <motion.div key={currentIndex} style={wordStyle} layout > {splitIntoCharacters(texts[currentIndex]).map((char, i) => ( <motion.div key={i} initial={{ y: '100%' }} animate={{ y: 0 }} exit={{ y: '-120%' }} transition={{ delay: i * 0.05 }} > {char} </motion.div> ))} </motion.div> </AnimatePresence> </motion.div>
为什么这样能行?
- 外层布局容器的
layout:它会自动监听内部所有元素的盒模型变化,包括新旧单词容器同时存在时的尺寸差异,从而计算出平滑的宽度过渡动画。 - AnimatePresence的
mode="pop":这个是关键!它会让旧单词容器的exit动画和新单词容器的enter动画同时进行,而且新旧元素会暂时同时存在于DOM中。这样布局容器就能在整个动画过程中“看到”新旧宽度的变化,不会出现跳变。 - 单词容器的
layout:给每个单词的容器也加上layout,能让旧单词的宽度在exit动画过程中,逐渐过渡到新单词的宽度,和外层容器的缩放形成呼应,避免突兀。 - 字符的exit动画:因为AnimatePresence直接包裹着单词容器,当
currentIndex变化时,旧单词容器会被AnimatePresence捕获,触发内部所有字符的exit动画(就是你写的y轴向上移出),而且每个字符的延迟效果也能正常生效。
你之前踩坑的原因复盘
- 当你把AnimatePresence包在最外层时,它的直接子元素是布局容器,而布局容器的key没变化(和currentIndex无关),所以AnimatePresence根本不知道里面的单词换了,自然不会触发exit动画;
- 当你把AnimatePresence塞到布局容器里但用了
mode="wait",它会等旧元素完全卸载后再挂载新元素,这时候布局容器的宽度会瞬间从旧值跳到新值,没有过渡的过程——因为中间没有“新旧元素共存”的阶段让它计算渐变。
这样调整之后,字符的进出动画、容器的宽度缩放应该就能完美配合了,你可以试试调整mode和layout的组合,看看哪种动画节奏最符合你的需求~
内容来源于stack exchange
相关产品推荐
相关产品推荐

