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

Reactjs与Sass下拉菜单:切换菜单项时的收起动画问题

React下拉菜单切换无收起动画的修复方案

核心问题

切换菜单项时,当前展开的下拉内容被直接移除(或通过display: none隐藏),导致CSS动画无法触发退出阶段。

具体修复步骤

1. 改用过渡属性替代display控制显示

将原有的keyframes动画改为transition控制,通过opacity、max-height和visibility实现平滑的显示/隐藏:

.dropdown-content {
  /* 初始隐藏状态 */
  visibility: hidden;
  opacity: 0;
  max-height: 0;
  overflow: hidden;
  transition: opacity 0.3s ease, max-height 0.3s ease, visibility 0.3s ease;
  /* 保留原有布局样式 */
  position: absolute;
  top: 100%;
  left: 0;
  background: #fff;
  border: 1px solid #eee;
}

.dropdown-content.open {
  /* 展开状态 */
  visibility: visible;
  opacity: 1;
  max-height: 500px; /* 设为足够容纳菜单内容的数值 */
}

2. 保留所有下拉内容的DOM节点

不要通过条件渲染({activeItem === item.id && <DropdownContent />})移除DOM,而是给所有下拉内容添加类控制显示:

// 原代码(有问题)
{activeItem === item.id && <DropdownContent />}

// 修改后
<DropdownContent className={activeItem === item.id ? 'open' : ''} />

这样所有下拉内容都保留在DOM中,切换时仅通过CSS类触发过渡动画。

3. 优化状态切换逻辑

如果需要切换时先收起当前菜单,再展开新菜单,可通过延迟状态更新实现:

const handleItemClick = (itemId) => {
  if (activeItem === itemId) {
    // 点击已展开的项,直接收起
    setActiveItem(null);
  } else {
    // 先收起当前菜单,再展开新菜单
    setActiveItem(null);
    setTimeout(() => {
      setActiveItem(itemId);
    }, 300); // 时长与transition的动画时长一致
  }
};

4. (可选)保留keyframes的处理方式

如果坚持使用keyframes,需要监听动画结束事件,确保动画完成后再更新DOM:

const [shouldRender, setShouldRender] = useState(true);

const handleAnimationEnd = () => {
  if (!isOpen) {
    setShouldRender(false);
  }
};

// 渲染时
{shouldRender && (
  <DropdownContent
    className={isOpen ? 'open' : 'close'}
    onAnimationEnd={handleAnimationEnd}
  />
)}

这种方式需要额外管理DOM的渲染状态,复杂度较高,推荐优先使用transition方案。

内容的提问来源于stack exchange,提问作者Negar Nasiri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 17:40:45