Next.js是否有类似window.onload的功能?实现页面完全加载后再显示
在Next.js中实现页面完全加载后再显示的方案
为什么loading.tsx没用?
loading.tsx是Next.js的路由加载骨架屏组件,仅在路由切换时的页面组件编译/加载阶段生效,不会监听页面内的图片、字体等静态资源加载完成事件,所以解决不了你遇到的Hero标题提前启动动画的问题。
方法一:全局监听所有资源加载(对应原生window.onload逻辑)
创建一个客户端组件作为全局包裹层,监听页面所有资源加载完成后再显示内容:
- 新建
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> ); }
- 在根布局中使用这个包裹层:
// 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
相关产品推荐
相关产品推荐

