如何在NextJS中实现仅刷新/首次加载的全屏加载器与页面淡入过渡
Next.js 实现首次加载全屏加载器 + 页面Fade导航过渡(基于Framer Motion)
一、仅首次/刷新显示的全屏加载器
要实现只在页面首次加载或刷新时显示的全屏加载器,核心是利用根布局的生命周期特性——App Router下根布局不会在页面路由切换时重新挂载,因此只需在首次挂载时触发加载逻辑即可。
实现代码(根layout.tsx)
'use client'; import { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { usePathname } from 'next/navigation'; export default function RootLayout({ children }) { const [isInitialLoading, setIsInitialLoading] = useState(true); const pathname = usePathname(); // 仅在根布局首次挂载时执行加载逻辑 useEffect(() => { const finishLoading = () => { // 这里可替换为实际的资源加载完成判断,比如等待数据、静态资源加载 setTimeout(() => setIsInitialLoading(false), 1200); }; // 检查页面是否已加载完成 if (document.readyState === 'complete') { finishLoading(); } else { window.addEventListener('load', finishLoading); return () => window.removeEventListener('load', finishLoading); } }, []); return ( <html lang="zh-CN"> <body className="m-0 p-0"> {/* 全屏加载器 */} {isInitialLoading && ( <motion.div initial={{ opacity: 1 }} animate={{ opacity: 0 }} transition={{ duration: 0.6 }} className="fixed inset-0 bg-white flex items-center justify-center z-[1000]" > {/* 自定义加载动画示例:旋转圆环 */} <motion.div animate={{ rotate: 360 }} transition={{ duration: 1.2, repeat: Infinity, ease: "linear" }} className="w-18 h-18 border-4 border-gray-100 border-t-indigo-600 rounded-full" /> </motion.div> )} {/* 页面内容过渡容器 */} <AnimatePresence mode="wait"> <motion.div key={pathname} initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: 0.5 }} className="min-h-screen" > {children} </motion.div> </AnimatePresence> </body> </html> ); }
关键逻辑说明
use client:启用客户端组件特性,支持React钩子和Framer Motion动画- 空依赖的
useEffect:仅在根布局首次挂载时执行,路由切换时不会重复触发,确保加载器只在首次/刷新时显示 window.load监听:等待页面所有资源(图片、脚本等)加载完成后再隐藏加载器,避免提前结束加载状态
二、页面间导航的Fade过渡效果
结合Framer Motion的AnimatePresence和Next.js的路由路径,实现页面切换时的淡入淡出效果:
核心实现要点
- 用
AnimatePresence包裹页面内容容器,它能检测组件的挂载/卸载状态,触发退出动画 - 给内容容器设置
key={pathname}:每次路由切换时,旧页面会触发exit动画,新页面触发initial和animate动画 mode="wait":等待旧页面的退出动画完成后,再挂载新页面,避免过渡时的内容重叠
自定义过渡参数
你可以调整transition的配置来匹配目标效果:
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] // 自定义缓动曲线,接近示例网站的过渡质感 }}
注意事项
- 如果使用服务器组件,根布局的客户端组件包裹不会影响服务器组件的渲染,动画依然正常生效
- 加载器的动画可以完全自定义,比如替换为品牌Logo的淡入动画,只需修改
motion.div内部的内容即可 - 若需要更复杂的加载逻辑(比如等待数据请求完成),可以将
setTimeout替换为数据加载完成的回调
内容的提问来源于stack exchange,提问作者Ugus
相关产品推荐
相关产品推荐

