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
相关产品推荐
相关产品推荐

