配置有效Key与动画后,AnimatePresence仍无法实现Tooltip退出动画
问题分析与解决方案
你的exit动画未生效的核心原因是:每个skill元素都独立渲染了一个Tooltip组件,且每个Tooltip内部的AnimatePresence仅负责自己内部的motion.div。当鼠标移出时,visible变为false导致motion.div被直接移除,React的批量更新机制可能让AnimatePresence无法及时捕获元素移除事件,从而跳过exit动画。
以下是两种可行的解决方法:
方案一:单Tooltip实例(推荐)
这种方式更高效,也完全符合Framer Motion的动画触发逻辑:
1. 修改父组件结构
只渲染一个全局Tooltip,用AnimatePresence包裹,根据showTooltip状态控制显示:
// 父组件内部 const [tooltipPosition, setTooltipPosition] = useState({ top: 0, left: 0 }); const renderList = sortedList.map((skill) => ( <div className='skill' key={skill.name} aria-label={skill.name} onMouseEnter={(e) => { setShowTooltip(skill.name); // 获取当前skill的位置,用于Tooltip定位 const rect = e.currentTarget.getBoundingClientRect(); setTooltipPosition({ top: rect.top - 40, // 根据需求调整偏移量 left: rect.left + rect.width / 2 - 60 // 居中对齐skill }); }} onMouseLeave={() => setShowTooltip(false)} > {skill.graphic} </div> )); return ( <div className='skills-container'> {renderList} {/* 全局唯一的Tooltip */} <AnimatePresence> {showTooltip && ( <Tooltip message={showTooltip} position={tooltipPosition} /> )} </AnimatePresence> </div> );
2. 简化Tooltip组件
去掉visible属性,直接由AnimatePresence控制动画:
const Tooltip = ({ message, position }) => ( <motion.div className='tooltip' style={position} key={message} variants={tooltipFade} initial='hidden' animate='visible' exit='exit' > <p>{ message }</p> </motion.div> );
方案二:保留多Tooltip实例,修复动画触发
如果必须为每个skill保留独立的Tooltip,可以通过取消条件渲染、用动画状态控制显示来修复:
修改Tooltip组件
const Tooltip = ({ visible, message }) => ( <div className='tooltip-wrapper'> <AnimatePresence initial={false}> <motion.div className='tooltip' key={message} variants={tooltipFade} animate={visible ? 'visible' : 'exit'} exit='exit' style={{ // 用opacity控制显示,避免直接移除元素 opacity: visible ? 1 : 0, pointerEvents: visible ? 'auto' : 'none' }} > <p>{ message }</p> </motion.div> </AnimatePresence> </div> );
这里取消了visible &&的条件渲染,改为通过animate属性触发exit动画,同时用pointerEvents避免隐藏时干扰交互。
内容的提问来源于stack exchange,提问作者singing
相关产品推荐
相关产品推荐

