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

React中菜单展开与收起的CSS Transition失效问题求助

修复菜单收起无动画的问题

你遇到的问题核心是:当isOpen变为false时,MenuBody被直接从DOM中移除,动画还没执行就消失了。下面给两种可行的修复方案:

方案一:用CSS Transition + 类切换(最简单推荐)

不用卸载组件,通过切换类来控制展开/收起的双向动画:

React代码调整

const [isOpen, setIsOpen] = useState(false);

return (
  <>
    <button onClick={() => setIsOpen(!isOpen)}>open menu</button>
    {/* 用类控制状态,不再直接卸载组件 */}
    <MenuBody isOpen={isOpen} />
  </>
);

const MenuBody = ({ isOpen }) => {
  return (
    <div className={`${styles.menuBody} ${isOpen ? styles.open : ''}`}>
      {/* 菜单内容 */}
    </div>
  );
};

CSS代码替换

删掉原来的keyframes,用transition实现双向过渡:

.menuBody {
  /* 收起状态的初始样式 */
  opacity: 0;
  visibility: hidden; /* 防止收起后误点 */
  transition: opacity 0.5s ease-in-out, visibility 0.5s ease-in-out;
  /* 你的其他原有样式 */
}

.menuBody.open {
  /* 展开状态 */
  opacity: 1;
  visibility: visible;
}

方案二:延迟卸载组件(适合必须卸载的场景)

如果一定要在收起后卸载组件,就监听动画结束事件,等动画跑完再移除:

React代码调整

import { useState, useEffect, useRef, forwardRef } from 'react';

const [isOpen, setIsOpen] = useState(false);
const [showMenu, setShowMenu] = useState(false);
const menuRef = useRef(null);

useEffect(() => {
  if (isOpen) {
    // 展开时直接显示
    setShowMenu(true);
  } else {
    // 收起时先触发动画,结束后再隐藏
    if (menuRef.current) {
      const onAnimationEnd = () => {
        setShowMenu(false);
        menuRef.current.removeEventListener('animationend', onAnimationEnd);
      };
      menuRef.current.addEventListener('animationend', onAnimationEnd);
    }
  }
}, [isOpen]);

return (
  <>
    <button onClick={() => setIsOpen(!isOpen)}>open menu</button>
    {showMenu && <MenuBody ref={menuRef} isClosing={!isOpen} />}
  </>
);

// 用forwardRef传递ref到内部元素
const MenuBody = forwardRef(({ isClosing }, ref) => {
  return (
    <div 
      ref={ref}
      className={`${styles.menuBody} ${isClosing ? styles.closing : ''}`}
    >
      {/* 菜单内容 */}
    </div>
  );
});

CSS代码补充

添加收起的动画:

/* 展开动画 */
@keyframes menuOpen {
  0% { opacity: 0; }
  100% { opacity: 1; }
}

/* 收起动画 */
@keyframes menuClose {
  0% { opacity: 1; }
  100% { opacity: 0; }
}

.menuBody {
  /* 原有样式 */
}

.menuBody:not(.closing) {
  animation: menuOpen 0.5s ease-in-out forwards;
}

.menuBody.closing {
  animation: menuClose 0.5s ease-in-out forwards;
}

注意点

  • 方案一里的visibility是必须的,不然菜单收起后还是能被点击到。
  • 方案二要记得移除事件监听器,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 16:55:22