NextJS中Window和document未定义:此前正常运行后失效
解决Next.js中
document未定义导致的视差效果故障 问题原因
Next.js默认采用服务端渲染(SSR),组件初始化逻辑会在服务端环境执行,而服务端没有浏览器的document对象。你通过useMemo直接获取:root元素的代码会在服务端运行,因此抛出document is not defined错误。
解决方案
将DOM相关的获取操作移至useEffect钩子中——useEffect仅在客户端渲染完成后执行,此时document对象已存在。同时优化视差处理逻辑,确保仅在客户端环境下执行DOM操作。
修改后的代码
Index.js
import Image from "next/image"; import Link from "next/link"; import { useState, useEffect } from "react"; import { FaDiscord } from "react-icons/fa"; export default function Home() { const [isVisible, setIsVisible] = useState(true); const [root, setRoot] = useState(null); useEffect(() => { // 客户端环境下获取root元素 setRoot(document.querySelector(":root")); // 滚动监听逻辑 const listenToScroll = () => { const heightToHideFrom = 150; const winScroll = document.body.scrollTop || document.documentElement.scrollTop; if (winScroll > heightToHideFrom) { isVisible && setIsVisible(false); } else { setIsVisible(true); } }; window.addEventListener("scroll", listenToScroll); return () => window.removeEventListener("scroll", listenToScroll); }, [isVisible]); const parallaxHandler = (e) => { if (!root) return; // 确保root存在再执行 const x = (e.clientX - window.innerWidth / 2) / 100; const y = (e.clientY - window.innerHeight / 2) / 100; root.style.setProperty("--posX", -x); root.style.setProperty("--posY", -y); }; return ( <> {/* HERO */} <section onMouseMove={parallaxHandler} className="w-[100vw] bg-[url(/Home/wave.svg)] bg-orange bg-contain bg-bottom bg-no-repeat parallax h-[100vh] pt-24 lg:px-0 px-4 lg:pt-0 lg:flex lg:text-left text-center justify-center align-middle" > <div className="self-center xl:mb-20 px-0 lg:px-20"> <h1 className="font-title sm:text-8xl text-5xl"> Text <br /> <span className="text-black"> Audio </span> </h1> <h2 className="font-poppins sm:text-2xl text-center lg:text-left text-xl uppercase py-4"> With crypto and fiat, coming soon... </h2> <Link href="https://discord.com/invite/" passHref> <a target="_blank"> <button className="flex rounded gap-2 text-md align-middle lg:mx-0 mx-auto bg-grey p-4"> <FaDiscord size="2em" color="#FB713A " className="cursor-pointer" /> <p className="my-auto text-orange"> Join our Discord </p> </button> </a> </Link> </div> <div className="relative max-h-[60%] lg:max-h-[100%] w-[471px] h-[549px] lg:w-[753px] lg:h-[878px] inline-block justify-center xl:flex-col sm:h-[586px] sm:w-[502px] width object-center"> <Image alt="app_bg" className="app_bg" src="/Home/hero_app.png" quality={100} layout="fill" objectFit="contain" priority /> </div> {isVisible && ( <Link href="#whatis"> <div className="cursor-pointer text-center absolute bottom-0 p-0 left-[40%] right-[40%]"> <div className="scroll__down"> <span className="scroll__mouse"> <span className="scroll__wheel"></span> </span> </div> <p className="text-orange text-xs font-semibold animate-pulse"> SCROLL TO EXPLORE{" "} </p> </div> </Link> )} </section> </> ); }
Styles.css(无需修改)
:root { --posX: 0; --posY: 0; } .parallax .app_bg { transform: translate(calc(var(--posX) * 1px), calc(var(--posY) * 1px)); }
额外说明
- 把
listenToScroll函数移到useEffect内部,避免依赖外部变量导致的不必要重渲染,同时确保仅在客户端执行。 - 在
parallaxHandler中添加root存在性判断,防止客户端初始化完成前触发事件导致的错误。
内容的提问来源于stack exchange,提问作者Demetris
相关产品推荐
相关产品推荐

