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

移动端React页面scrollY返回0,滚动显示h1/img元素失效问题排查

问题分析
  1. 初始状态错误:isVisible初始设为true,导致页面加载时直接渲染元素,违背了“滚动至视口才加载”的需求。
  2. 事件清理错误:useEffect的清理函数中错误地重复添加了touchmove事件,应该改为移除该事件。
  3. 滚动检测逻辑不可靠:依赖window.scrollY和其他元素高度计算触发条件,移动端可能因为以下原因导致scrollY始终为0:
    • 页面滚动容器不是window(比如body/html设置了overflow: hidden,滚动由内部容器承担)
    • 移动端浏览器的滚动行为(如弹性滚动、地址栏变化导致视口高度动态调整)
  4. 性能问题:监听scroll和touchmove事件会频繁触发回调,影响页面性能。
原生解决方案:使用Intersection Observer API

Intersection Observer是浏览器原生API,专门用于检测元素是否进入/离开视口,无需监听滚动事件,性能更优,且完美适配移动端。

修改后的代码

import React, { useEffect, useState, useRef } from 'react';
import Headshot from '../../../assets/images/about/Headshot';

const About = () => {
    const [isVisible, setIsVisible] = useState(false);
    const aboutRef = useRef(null); // 用于获取About容器的DOM引用

    useEffect(() => {
        const observer = new IntersectionObserver(
            ([entry]) => {
                // 当元素进入视口时设置isVisible为true,离开时可根据需求调整
                if (entry.isIntersecting) {
                    setIsVisible(true);
                    // 若只需触发一次动画,可在此处停止观察
                    // observer.unobserve(entry.target);
                } else {
                    setIsVisible(false);
                }
            },
            {
                root: null, // 使用视口作为根容器
                rootMargin: '0px', // 元素完全进入视口时触发
                threshold: 0.1 // 元素10%进入视口时触发,可按需调整
            }
        );

        const currentRef = aboutRef.current;
        if (currentRef) {
            observer.observe(currentRef);
        }

        // 清理函数:停止观察并销毁观察者
        return () => {
            if (currentRef) {
                observer.unobserve(currentRef);
            }
            observer.disconnect();
        };
    }, []);

    return ( 
        <>
            <div className='container aboutContainer' id="About" ref={aboutRef}>
                {isVisible && (
                    <>
                        <h1 className="aboutH1">This is Me</h1>
                        <div className="headshot">
                            <Headshot />
                            <img 
                                src="/assets/images/about/headshot.webp" 
                                alt="Headshot" 
                                id="headshotImg"
                            />
                        </div>
                    </>
                )}
            </div>
        </>
    );
}

export default About

关键说明

  1. Intersection Observer配置:
    • root: null:使用浏览器视口作为检测的根容器
    • rootMargin:可以设置类似CSS margin的值,比如'-50px'表示元素进入视口50px时触发
    • threshold:设置元素进入视口的比例(0~1),0表示元素刚接触视口就触发,1表示完全进入视口才触发
  2. 元素引用:使用useRef获取About容器的DOM元素,确保观察者能正确监听目标元素
  3. 初始状态修正:将isVisible初始设为false,确保元素默认不渲染
  4. 动画触发:配合CSS动画,只需给aboutH1和headshot添加对应的类,当isVisible为true时,元素渲染并触发动画

额外优化建议

  • 图片懒加载:可以给img标签添加loading="lazy"属性,配合Intersection Observer实现更彻底的懒加载
  • 动画性能:使用transform和opacity实现CSS动画,避免触发重排重绘

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 15:20:48