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

使用useEffect实现的React视差效果在不同屏幕下无响应如何解决

问题核心原因

  • 代码中所有滚动阈值(600px/1100px/1400px/1700px)都是固定像素值,仅匹配单台设备的视口高度,屏幕尺寸变化后滚动触发节点完全错位
  • 图片宽度写死为280px,响应式布局下图片尺寸变化后位移计算完全失效
  • 没有处理窗口resize场景,缩放屏幕后所有参数不会自动更新
  • 未做滚动事件节流,高频触发容易导致渲染卡顿

优化方案

不需要全部替换为vw单位,通过动态计算相对值即可实现响应式适配,修改后的代码如下:

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

export default function App() {
  const [index, setIndex] = useState(false);
  const [number, setNumber] = useState(false);

  // 节流函数,避免高频事件触发卡顿
  const throttle = (func, delay) => {
    let lastCall = 0;
    return (...args) => {
      const now = new Date().getTime();
      if (now - lastCall < delay) return;
      lastCall = now;
      func(...args);
    };
  };

  const handleParallax = useCallback(() => {
    const scrollY = window.scrollY;
    const viewportHeight = window.innerHeight;
    const img = document.getElementById("moveLeft");
    const text = document.getElementById("moveUp");
    const text2 = document.getElementById("text2");
    const text3 = document.getElementById("text3");
    const text4 = document.getElementById("text4");
    
    // 动态获取图片宽度,适配响应式图片
    const imgWidth = img?.offsetWidth || 280;

    // 用视口高度比例替换固定像素阈值,适配所有屏幕尺寸
    const threshold1 = viewportHeight * 0.8;
    const threshold2 = viewportHeight * 1.5;
    const threshold3 = viewportHeight * 1.9;
    const threshold4 = viewportHeight * 2.3;

    if (text) text.style.marginTop = `-${scrollY * 0.5}px`;
    if (text2) text2.style.transform = `translateX(${scrollY * 1.3}px)`;
    if (text3) text3.style.transform = `translateX(-${scrollY * 1.3}px)`;
    if (text4) text4.style.transform = `translateX(${scrollY * 1.3}px)`;

    if (img) {
      if (scrollY > threshold2) {
        img.style.transform = `translateX(${-1 * (scrollY * 0.8 - threshold2 * 0.8) + 80 + imgWidth}px)`;
      } else if (scrollY > threshold1) {
        img.style.transform = `translateX(${scrollY * 0.8 - threshold1 * 0.8 - imgWidth}px)`;
      } else {
        img.style.transform = `translateX(-${scrollY * 0.5}px)`;
      }
    }

    setNumber(scrollY > threshold3);
    setIndex(scrollY > threshold4);
  }, []);

  useEffect(() => {
    const throttledParallax = throttle(handleParallax, 16); // 约60帧刷新,兼顾流畅度和性能
    // 同时监听滚动和窗口缩放事件
    window.addEventListener('scroll', throttledParallax);
    window.addEventListener('resize', throttledParallax);
    // 初始化时执行一次,避免刷新页面时样式错位
    throttledParallax();
    
    return () => {
      window.removeEventListener('scroll', throttledParallax);
      window.removeEventListener('resize', throttledParallax);
    };
  }, [handleParallax]);

  return (
    <>
      <div className="App">
        <div className="middletext" id="moveUp" style={{ zIndex: "9" }}>
          Random Text
        </div>

        <div className="inflow">
          <div className="positioner">
            <div className="fixed" style={{ zIndex: "11" }}>
              <div id="moveLeft">
                <img
                  alt="passport"
                  src="https://cdn.britannica.com/87/122087-050-1C269E8D/Cover-passport.jpg"
                />
              </div>
            </div>
          </div>
          <div className="halfWindow" style={{ zIndex: "8" }}></div>
          <div>
            <div className="fixedText" style={{ zIndex: "7" }}>
              <div id="text2" className="text2">
                Random Text
              </div>
            </div>
          </div>
          <div className="secondhalfWindow" style={{ zIndex: index ? "10" : "6" }}></div>
          <div>
            <div
              className="secondfixedText"
              style={{
                zIndex: index ? "9" : "5",
                display: "block"
              }}
            >
              <div id="text3" className="text3">
                Random Text 2
              </div>
            </div>
          </div>

          <div className="thirdhalfWindow" style={{ zIndex: "4" }}></div>
          <div>
            <div
              className="thirdfixedText"
              style={{
                zIndex: number ? "10" : "3"
              }}
            >
              <div id="text4" className="text4">
                Random Text 3
              </div>
            </div>
          </div>
        </div>
      </div>
    </>
  );
}

适配调整说明

如果需要更精细的效果比例调整,直接修改阈值对应的视口高度系数即可,不需要修改任何固定像素值,所有参数会自动适配不同屏幕尺寸。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 05:36:02