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

React中递归函数内scrollBy执行不符合预期问题排查

问题原因及解决方案

核心原因

  1. 页面高度获取错误:你用document.body.scrollHeight计算页面总高度,但在现代浏览器标准模式(带DOCTYPE声明)下,document.body.scrollHeight通常仅等于视口高度,正确的页面总高度应该从document.documentElement.scrollHeight获取。这导致第一次滚动后,代码错误判断剩余滚动距离不足20px,直接停止递归调用。
  2. 滚动调度间隔不合理:setTimeout(scrollBottom, 0)的间隔为0,浏览器事件循环可能无法及时调度后续滚动任务,同时滚动效果也会过于生硬。

另外需确认触发区域定位:如果触发区域是absolute定位,页面滚动时它会跟着移动,导致鼠标离开触发区域,overBottomTrigger.current变为false也会停止滚动——建议将触发区域设为fixed定位,固定在页面底部。

修复后的代码

import { useCallback, useRef, ReactNode } from 'react';
import styles from './AutoScroll.module.css';

export interface IAutoScrollProps {
  children: ReactNode;
}

const AutoScroll = ({ children }: IAutoScrollProps) => {
  const bottomTriggerClass = `${styles['bottom-trigger']} ${styles['trigger']} ${styles['horizontal']}`;
  const overBottomTrigger = useRef(false);

  const scrollBottom: () => void = useCallback(() => {
    window.scrollBy(0, 10);

    if (!overBottomTrigger.current) return;

    // 兼容不同浏览器的页面总高度计算
    const totalPageHeight = Math.max(
      document.body.scrollHeight,
      document.documentElement.scrollHeight
    );
    const remainingScroll = totalPageHeight - window.innerHeight - window.scrollY;
    if (remainingScroll < 20) return;

    // 用16ms间隔(接近60fps)实现平滑滚动
    setTimeout(scrollBottom, 16);
  }, []);

  const onBottomTriggerMouseEnter = useCallback(() => {
    overBottomTrigger.current = true;
    scrollBottom();
  }, [scrollBottom]);

  const onBottomTriggerMouseLeave = useCallback(() => {
    overBottomTrigger.current = false;
  }, []);

  return (
    <div>
      <section className="autoScroll-container p-relative">
        {children}
      </section>
      <span
        className={bottomTriggerClass}
        onMouseEnter={onBottomTriggerMouseEnter}
        onMouseLeave={onBottomTriggerMouseLeave}
      ></span>
    </div>
  );
};

export default AutoScroll;

额外样式建议(确保触发区域正常工作)

在CSS模块中添加:

.bottom-trigger {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 40px; /* 调整为适合的触发区域高度 */
  opacity: 0; /* 透明不遮挡内容 */
  pointer-events: auto; /* 确保能捕获鼠标事件 */
  z-index: 999; /* 防止被其他元素遮挡 */
}

内容的提问来源于stack exchange,提问作者Андрей

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 12:45:34