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

如何在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的路由路径,实现页面切换时的淡入淡出效果:

核心实现要点

  1. 用AnimatePresence包裹页面内容容器,它能检测组件的挂载/卸载状态,触发退出动画
  2. 给内容容器设置key={pathname}:每次路由切换时,旧页面会触发exit动画,新页面触发initial和animate动画
  3. mode="wait":等待旧页面的退出动画完成后,再挂载新页面,避免过渡时的内容重叠

自定义过渡参数

你可以调整transition的配置来匹配目标效果:

transition={{ 
  duration: 0.6, 
  ease: [0.22, 1, 0.36, 1] // 自定义缓动曲线,接近示例网站的过渡质感
}}

注意事项

  • 如果使用服务器组件,根布局的客户端组件包裹不会影响服务器组件的渲染,动画依然正常生效
  • 加载器的动画可以完全自定义,比如替换为品牌Logo的淡入动画,只需修改motion.div内部的内容即可
  • 若需要更复杂的加载逻辑(比如等待数据请求完成),可以将setTimeout替换为数据加载完成的回调

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 02:03:17