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

Next.js 13中Headless UI Transition与Dialog进入动画失效问题排查

问题分析与解决方案

这不是Headless UI的Bug,是你的代码结构问题导致过渡效果仅在关闭时生效。

问题根源

你把Transition组件直接包裹了整个Dialog,但Dialog是Headless UI的抽象组件,它不会将Transition的过渡类传递给内部实际渲染的DOM元素(那个带背景的fixed div)。当modal从false切换到true时,背景div直接显示,没有触发Transition的进入动画;而关闭时,组件卸载过程中触发了leave动画,所以能看到效果。

修复方案

将Transition组件移到Dialog内部,直接包裹需要过渡的背景div,让过渡类直接作用到这个DOM元素上:

"use client";
import { Dialog, Transition } from "@headlessui/react";
import { useDispatch, useSelector } from "react-redux";
import { RootState } from "@/redux/store";
import { setShowModal } from "@/redux/slices/modalSlice";
import { Fragment } from "react";

function Modal() {
  const dispatch = useDispatch();
  const modal = useSelector((state: RootState) => state.modal.value);

  return (
    <Dialog
      onClose={() => dispatch(setShowModal(false))}
      className={`relative z-50`}
    >
      <Transition
        appear={true}
        as={Fragment}
        show={modal}
        enter="transition-all duration-1000 ease-in-out"
        enterFrom="opacity-0"
        enterTo="opacity-100"
        leave="transition-all duration-300 ease-in-out"
        leaveFrom="opacity-100"
        leaveTo="opacity-0"
      >
        <div
          className={`fixed inset-0 flex items-center justify-center bg-slate-900/80 p-4 text-white`}
        >
          <Dialog.Panel>
            <Dialog.Title>Deactivate account</Dialog.Title>
            <Dialog.Description>
              This will permanently deactivate your account
            </Dialog.Description>

            <p>
              Are you sure you want to deactivate your account? All of your data
              will be permanently removed. This action cannot be undone.
            </p>

            <button onClick={() => dispatch(setShowModal(false))}>
              Deactivate
            </button>
            <button onClick={() => dispatch(setShowModal(false))}>
              Cancel
            </button>
          </Dialog.Panel>
        </div>
      </Transition>
    </Dialog>
  );
}

export default Modal;

额外优化(可选)

如果想让对话框面板也有过渡效果,可以给Dialog.Panel嵌套一个Transition,添加缩放+透明度动画:

<Transition
  as={Fragment}
  show={modal}
  enter="transition-all duration-500 ease-out"
  enterFrom="scale-95 opacity-0"
  enterTo="scale-100 opacity-100"
  leave="transition-all duration-300 ease-in"
  leaveFrom="scale-100 opacity-100"
  leaveTo="scale-95 opacity-0"
>
  <Dialog.Panel className="bg-white p-6 rounded-lg shadow-xl">
    {/* 面板内容 */}
  </Dialog.Panel>
</Transition>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 16:23:28