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

使用window.innerWidth获取屏幕宽报window未定义及响应式视差实现问题

问题解决指南

一、ReferenceError: window is not defined报错消除方案

报错原因

你当前的项目大概率启用了服务端渲染(SSR/SSG,比如Next.js、Gatsby这类框架),服务端运行代码时不存在window对象,直接在组件顶层访问window就会抛出该错误;而CodeSandbox是纯客户端渲染环境,代码仅在浏览器端运行,所以不会触发报错。同时你的代码把useEffect放在条件判断内部,也违反了React Hook不能在条件/循环/嵌套函数中调用的规则,会导致Hook执行顺序异常。

修复步骤

  1. 把useEffect移到组件顶层,所有访问window的逻辑都放到useEffect内部执行
  2. 如果需要动态获取屏幕宽度,可通过状态管理宽度值,同时监听窗口大小变化实现实时响应
  3. 访问window前可增加typeof window !== 'undefined'判断做兼容

修复后的参考代码

import { useState, useEffect, useRef } from 'react';

export default function App() {
  const [number, setNumber] = useState(false);
  // 存储屏幕宽度
  const [windowWidth, setWindowWidth] = useState(0);
  // 用ref代替getElementById,更符合React规范
  const imgRef = useRef(null);
  const textRef = useRef(null);
  const text2Ref = useRef(null);

  useEffect(() => {
    // 仅在客户端执行的逻辑
    if (typeof window === 'undefined') return;

    // 初始化宽度+监听窗口变化更新宽度
    const updateWidth = () => setWindowWidth(window.innerWidth);
    updateWidth();
    window.addEventListener('resize', updateWidth);

    // 滚动逻辑
    const changeBackground = () => {
      // 宽度小于1000时不执行视差逻辑
      if (windowWidth < 1000) return;

      const value = window.scrollY;
      const img = imgRef.current;
      const text = textRef.current;
      const text2 = text2Ref.current;
      if (!img || !text || !text2) return;

      const imgWidth = 280;
      text.style.marginTop = `-${value * 0.5}px`;
      text2.style.transform = `translateX(${value * 1.3}px)`;

      if (value > 600 && value <= 1400) {
        img.style.transform = `translateX(${value * 0.8 - 480 - imgWidth}px)`;
      } else if (value <= 600) {
        img.style.transform = `translateX(-${value * 0.5}px)`;
      } else if (value > 1400 && value <= 1700) {
        img.style.transform = `translateX(${-1 * (value * 0.8 - 1120) + 80 + imgWidth}px)`;
      }

      setNumber(value > 1700);
    };

    window.addEventListener("scroll", changeBackground);
    // 清理函数
    return () => {
      window.removeEventListener("resize", updateWidth);
      window.removeEventListener("scroll", changeBackground);
    };
  }, [windowWidth]); // 宽度变化时重新绑定逻辑

  // 渲染时给元素绑定ref
  return (
    <div>
      <img ref={imgRef} id="moveLeft" alt="视差图" />
      <p ref={textRef} id="moveUp">测试文本</p>
      <p ref={text2Ref}>第二个文本</p>
      {/* 其他页面内容 */}
    </div>
  )
}

二、更优的响应式视差实现方案

不需要为每个屏幕宽度单独写规则的实现思路如下:

  • 优先使用CSS滚动驱动动画实现视差:现在主流浏览器已经支持scroll()时间线,直接用CSS就能实现响应式视差,完全不需要JS操作DOM,性能更好,天然支持响应式。示例代码:
/* 给需要视差上移的文本添加样式 */
.move-up {
  animation: moveUp linear both;
  animation-timeline: scroll(root);
  animation-range: entry 0% cover 30%;
}

@keyframes moveUp {
  to {
    transform: translateY(-10vh); /* 用相对单位,自动适配不同屏幕 */
  }
}
  • 如果需要兼容旧浏览器,JS实现时所有偏移量用相对单位(vw/vh/百分比)代替硬编码的像素值,偏移系数可以根据宽度动态计算,不需要为每个断点单独写判断逻辑
  • 避免直接操作DOM样式,可把计算出的偏移值存到CSS变量上,由CSS根据媒体查询适配不同屏幕的表现,逻辑更清晰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 23:36:04