React-Framer Motion Layout属性使用异常问题求助
解决Framer Motion中列表退出与相邻元素平滑过渡的冲突问题
要同时实现列表优雅退出DOM和相邻列表平滑移动,核心是让外层容器感知布局变化,同时给待移除的列表保留AnimatePresence的卸载监听,具体实现步骤如下:
关键实现逻辑
- 外层布局容器:用
motion.div包裹两个列表,添加layout属性,让容器监听内部元素的布局变化,驱动相邻元素的平滑过渡。 - 待移除列表的处理:给该列表(
motion.ul)外层套AnimatePresence,同时给motion.ul添加layout和exit动画,确保它在卸载时逐步收缩消失,而非直接隐藏。 - 保留子项原有逻辑:继续使用
AnimatePresence处理列表项的删除动画,和父级列表的动画形成层级联动。
完整代码示例
import { motion, AnimatePresence } from "framer-motion"; const ListGroup = ({ listA, listB, onRemoveItem }) => { return ( {/* 外层容器:监听内部布局变化,驱动相邻列表移动 */} <motion.div layout className="list-group-container"> {/* 待移除的列表A:仅当有子项时渲染 */} <AnimatePresence> {listA.length > 0 && ( <motion.ul key="list-a" layout exit={{ opacity: 0, height: 0, marginTop: 0, marginBottom: 0, paddingTop: 0, paddingBottom: 0 }} transition={{ duration: 0.3, delay: 0.2 }} {/* 延迟触发,等子项先退出 */} className="list" > <AnimatePresence> {listA.map(item => ( <motion.li key={item.id} exit={{ opacity: 0, height: 0, margin: 0, padding: 0 }} transition={{ duration: 0.2 }} className="list-item" > {item.text} <button onClick={() => onRemoveItem('A', item.id)}>删除</button> </motion.li> ))} </AnimatePresence> </motion.ul> )} </AnimatePresence> {/* 始终存在的列表B */} <motion.ul layout className="list"> <AnimatePresence> {listB.map(item => ( <motion.li key={item.id} exit={{ opacity: 0, height: 0, margin: 0, padding: 0 }} transition={{ duration: 0.2 }} className="list-item" > {item.text} <button onClick={() => onRemoveItem('B', item.id)}>删除</button> </motion.li> ))} </AnimatePresence> </motion.ul> </motion.div> ); };
核心细节说明
- 外层
motion.div layout:这是让相邻列表平滑移动的核心,它会自动计算容器内元素的布局变化,生成过渡动画。 - 列表的
exit动画:必须设置height:0、margin:0、padding:0这类影响布局的属性,否则列表会直接隐藏,外层容器无法感知到布局变化,相邻元素也就不会平滑移动。 - 动画延迟:给列表的退出动画添加
delay,让子项先完成退出动画,再触发列表的收缩,视觉上更连贯。 - 唯一
key:待移除的列表必须设置唯一key,AnimatePresence依赖key来识别元素的挂载/卸载状态。
内容的提问来源于stack exchange,提问作者Y D
相关产品推荐
相关产品推荐

