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

配置有效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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 10:07:50