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

Next.js是否有类似window.onload的功能?实现页面完全加载后再显示

在Next.js中实现页面完全加载后再显示的方案

为什么loading.tsx没用?

loading.tsx是Next.js的路由加载骨架屏组件,仅在路由切换时的页面组件编译/加载阶段生效,不会监听页面内的图片、字体等静态资源加载完成事件,所以解决不了你遇到的Hero标题提前启动动画的问题。


方法一:全局监听所有资源加载(对应原生window.onload逻辑)

创建一个客户端组件作为全局包裹层,监听页面所有资源加载完成后再显示内容:

  1. 新建app/FullLoadWrapper.tsx客户端组件:
'use client';

import { useState, useEffect } from 'react';

export default function FullLoadWrapper({ children }: { children: React.ReactNode }) {
  const [isAllLoaded, setIsAllLoaded] = useState(false);

  useEffect(() => {
    const handlePageLoad = () => setIsAllLoaded(true);

    // 如果页面已经加载完成(比如客户端路由跳转时),直接触发
    if (document.readyState === 'complete') {
      handlePageLoad();
    } else {
      window.addEventListener('load', handlePageLoad);
      // 清理监听
      return () => window.removeEventListener('load', handlePageLoad);
    }
  }, []);

  // 用visibility和opacity控制显示,避免布局跳动
  return (
    <div 
      style={{ 
        visibility: isAllLoaded ? 'visible' : 'hidden',
        opacity: isAllLoaded ? 1 : 0,
        transition: 'opacity 0.3s ease-out'
      }}
    >
      {children}
    </div>
  );
}
  1. 在根布局中使用这个包裹层:
// app/layout.tsx
import FullLoadWrapper from './FullLoadWrapper';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="zh-CN">
      <body>
        <FullLoadWrapper>{children}</FullLoadWrapper>
      </body>
    </html>
  );
}

方法二:仅监听关键资源(比如Hero图片)

如果只需要等Hero Banner图片加载完再启动标题动画,直接用Next.js Image组件的onLoad事件控制动画状态:

'use client';

import { useState } from 'react';
import Image from 'next/image';

export default function HeroBanner() {
  const [isHeroReady, setIsHeroReady] = useState(false);

  return (
    <div className="relative h-screen">
      <Image
        src="/hero-banner.jpg"
        alt="Hero 横幅"
        fill
        objectFit="cover"
        onLoad={() => setIsHeroReady(true)}
      />
      <h1 
        className={`absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-white text-4xl
          ${isHeroReady ? 'fade-in' : 'opacity-0'}`}
      >
        我的Hero标题
      </h1>
    </div>
  );
}

对应的CSS:

.fade-in {
  opacity: 1;
  transition: opacity 0.6s ease-in-out;
}

方法三:额外处理字体加载

如果需要等自定义字体加载完成,可在客户端组件中监听字体加载状态:

'use client';

import { useState, useEffect } from 'react';

export default function FontAwareWrapper({ children }: { children: React.ReactNode }) {
  const [fontsLoaded, setFontsLoaded] = useState(false);

  useEffect(() => {
    async function waitForFonts() {
      await document.fonts.ready;
      setFontsLoaded(true);
    }
    waitForFonts();
  }, []);

  return fontsLoaded ? <>{children}</> : null;
}

可以把这个组件和前面的FullLoadWrapper结合,同时监听资源和字体加载。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 19:12:48