You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React-Framer Motion Layout属性使用异常问题求助

解决Framer Motion中列表退出与相邻元素平滑过渡的冲突问题

要同时实现列表优雅退出DOM和相邻列表平滑移动,核心是让外层容器感知布局变化,同时给待移除的列表保留AnimatePresence的卸载监听,具体实现步骤如下:

关键实现逻辑

  1. 外层布局容器:用motion.div包裹两个列表,添加layout属性,让容器监听内部元素的布局变化,驱动相邻元素的平滑过渡。
  2. 待移除列表的处理:给该列表(motion.ul)外层套AnimatePresence,同时给motion.ul添加layout和exit动画,确保它在卸载时逐步收缩消失,而非直接隐藏。
  3. 保留子项原有逻辑:继续使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 05:22:44