使用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
相关产品推荐
相关产品推荐

