ui: 页面切换过渡动画 — AnimatePresence 淡入滑出效果
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
"use client";
|
||||
|
||||
import { useContext, useRef, type PropsWithChildren } from "react";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { LayoutRouterContext } from "next/dist/shared/lib/app-router-context.shared-runtime";
|
||||
|
||||
/**
|
||||
* Preserves the previous route's React context during the exit animation
|
||||
* so the old page doesn't break while fading out.
|
||||
*/
|
||||
function FrozenRoute({ children }: PropsWithChildren) {
|
||||
const ctx = useContext(LayoutRouterContext);
|
||||
const frozen = useRef(ctx).current;
|
||||
return (
|
||||
<LayoutRouterContext.Provider value={frozen}>
|
||||
{children}
|
||||
</LayoutRouterContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
const variants = {
|
||||
enter: { opacity: 0, y: 12 },
|
||||
center: { opacity: 1, y: 0 },
|
||||
exit: { opacity: 0, y: -12 },
|
||||
};
|
||||
|
||||
export default function PageTransition({ children }: PropsWithChildren) {
|
||||
const pathname = usePathname();
|
||||
|
||||
return (
|
||||
<AnimatePresence mode="wait" initial={false}>
|
||||
<motion.div
|
||||
key={pathname}
|
||||
variants={variants}
|
||||
initial="enter"
|
||||
animate="center"
|
||||
exit="exit"
|
||||
transition={{ duration: 0.2, ease: [0.25, 0.1, 0.25, 1] }}
|
||||
>
|
||||
<FrozenRoute>{children}</FrozenRoute>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user