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

Next.js+Tailwind模态框动画失效且无法从DOM移除问题求助

解决Next.js模态框关闭动画与DOM移除冲突问题

问题分析

当前模态框存在两个核心问题:

  • 直接用isOpen控制DOM渲染会打断关闭动画流程
  • useDelayUnmount的状态逻辑与组件渲染不同步,且关闭按钮属性错误导致无法正常交互

修复步骤

1. 修正useDelayUnmount Hook逻辑

优化状态更新逻辑,避免不必要的重渲染,确保仅在isMounted变化时触发延迟:

function useDelayUnmount(isMounted: boolean, delayTime: number) {
  const [shouldRender, setShouldRender] = useState(isMounted);

  useEffect(() => {
    let timeoutId: NodeJS.Timeout;
    if (isMounted) {
      setShouldRender(true);
    } else {
      timeoutId = setTimeout(() => setShouldRender(false), delayTime);
    }

    return () => clearTimeout(timeoutId);
  }, [isMounted, delayTime]);

  return shouldRender;
}

2. 调整模态框组件渲染逻辑

保证overlay和模态框在动画期间保持DOM存在,仅在动画完成后移除,同时修复关闭按钮的属性错误:

const Modal: React.FC<PropsWithChildren & IModal> = ({
  children,
  isOpen,
  nodeId,
  onClose,
  className,
}) => {
  const shouldRender = useDelayUnmount(isOpen, 300); // 与transition时长保持一致

  if (!shouldRender) return null;

  return ReactDOM.createPortal(
    <>
      {/* overlay在渲染期间始终存在,通过isOpen控制透明度动画 */}
      <span 
        onClick={onClose} 
        className={`${classes.overlay} ${isOpen ? '' : classes.overlayHidden}`}
      />
      <div
        className={`${classes.modal} ${isOpen ? classes.active : ''} ${className}`}
      >
        <div>
          <span
            onClick={onClose}
            className='text-2xl cursor-pointer' {/* 修正iconName为className */}
          >×</span>
        </div>
        {children}
      </div>
    </>,
    nodeId ? document.getElementById(nodeId)! : document.body
  );
};

3. 更新SCSS样式,补充完整过渡动画

确保overlay和模态框的过渡时长与useDelayUnmount的延迟时间严格匹配:

.overlay {
  @apply fixed top-0 left-0 bottom-0 right-0 w-full h-full bg-black opacity-30 backdrop-blur-sm;
  transition: opacity 0.3s ease; // 添加overlay过渡动画
}

.overlayHidden {
  @apply opacity-0; // 关闭时逐步透明
}

.modal {
  @apply fixed w-[600px] min-h-[250px] p-4 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white rounded-xl
  opacity-0 invisible transition-all duration-300; // 统一过渡时长
}

.active {
  @apply opacity-100 visible; // 移除重复的translate,初始已设置居中
}

4. 首页组件保持原逻辑即可

核心原理

  • useDelayUnmount在isOpen变为false时,延迟一段时间再将shouldRender设为false,确保动画完整执行
  • overlay和模态框在shouldRender为true时始终存在,通过isOpen切换样式类触发过渡动画
  • 过渡时长与延迟时间严格对齐,保证动画结束后再从DOM中移除组件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 15:45:03