使用App Router的Next.js静态页面加载前显示加载界面求助
实现Next.js App Router静态导出页面的加载界面
针对静态导出的Next.js App Router项目,你可以通过以下两种方案实现页面完全加载前的加载界面:
方案一:React客户端组件封装加载逻辑
创建一个客户端组件来管理加载状态,利用浏览器的load事件和document.readyState判断页面资源是否加载完成:
- 创建客户端组件
app/components/LoadingWrapper.tsx
'use client'; import { useEffect, useState } from 'react'; export default function LoadingWrapper({ children }: { children: React.ReactNode }) { const [isLoading, setIsLoading] = useState(true); useEffect(() => { const finishLoading = () => setIsLoading(false); // 检查当前文档状态,若已加载完成直接结束 if (document.readyState === 'complete') { finishLoading(); } else { // 监听全局load事件(所有资源加载完成触发) window.addEventListener('load', finishLoading); // 监听文档状态变化,兜底处理 document.addEventListener('readystatechange', () => { if (document.readyState === 'complete') finishLoading(); }); } // 组件卸载时移除事件监听,避免内存泄漏 return () => { window.removeEventListener('load', finishLoading); document.removeEventListener('readystatechange', finishLoading); }; }, []); if (isLoading) { return ( <div className="fixed inset-0 flex items-center justify-center bg-white z-50"> <div className="w-16 h-16 border-4 border-gray-200 border-t-blue-500 rounded-full animate-spin"></div> </div> ); } return <>{children}</>; }
- 在根布局
app/layout.tsx中使用该组件包裹页面内容
import LoadingWrapper from './components/LoadingWrapper'; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="zh-CN"> <body> <LoadingWrapper>{children}</LoadingWrapper> </body> </html> ); }
方案二:初始HTML加载界面(更适合无JS缓存场景)
如果希望用户在客户端JS加载前就能看到加载界面,可以直接在根布局的HTML中添加静态加载元素,再通过客户端脚本移除:
修改app/layout.tsx:
'use client'; import { useEffect } from 'react'; export default function RootLayout({ children, }: { children: React.ReactNode; }) { useEffect(() => { const loader = document.getElementById('initial-loader'); if (!loader) return; const removeLoader = () => loader.remove(); if (document.readyState === 'complete') { removeLoader(); } else { window.addEventListener('load', removeLoader); return () => window.removeEventListener('load', removeLoader); } }, []); return ( <html lang="zh-CN"> <body> {/* 静态加载界面,浏览器加载HTML时直接显示 */} <div id="initial-loader" className="fixed inset-0 flex items-center justify-center bg-white z-50"> <div className="w-16 h-16 border-4 border-gray-200 border-t-blue-500 rounded-full animate-spin"></div> </div> {children} </body> </html> ); }
注意事项
确保你的next.config.js已配置静态导出:
/** @type {import('next').NextConfig} */ const nextConfig = { output: 'export', }; module.exports = nextConfig;
两种方案的核心逻辑都是:在客户端JS执行时,判断当前页面资源是否已加载完成,未完成则监听load事件,完成后隐藏加载界面;同时处理缓存场景下页面已加载完成的情况。
内容的提问来源于stack exchange,提问作者Muhib Al Hasan
相关产品推荐
相关产品推荐

