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

使用App Router的Next.js静态页面加载前显示加载界面求助

实现Next.js App Router静态导出页面的加载界面

针对静态导出的Next.js App Router项目,你可以通过以下两种方案实现页面完全加载前的加载界面:

方案一:React客户端组件封装加载逻辑

创建一个客户端组件来管理加载状态,利用浏览器的load事件和document.readyState判断页面资源是否加载完成:

  1. 创建客户端组件 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}</>;
}
  1. 在根布局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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 08:42:46