React滚动百分比指示器数值跳变怎么办?

司空蒙蒙 阅读 12

我在做页面滚动指示功能时遇到了问题,当快速滚动时百分比数值会突然跳变,不太流畅。我尝试用window.scrollY除以文档高度计算,但感觉响应不及时。

这是我的组件代码:


import { useState, useEffect } from 'react';

function ScrollIndicator() {
  const [scrollPercent, setScroll] = useState(0);

  useEffect(() => {
    const handleScroll = () => {
      const scrollY = window.scrollY;
      const height = document.documentElement.scrollHeight - window.innerHeight;
      const percent = (scrollY / height) * 100;
      setScroll(percent);
    };
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  return <div>滚动了{scrollPercent.toFixed(0)}%</div>;
}
export default ScrollIndicator;

测试时发现数值会在快速滚动时出现0.5秒左右的延迟,而且当内容高度变化时计算结果会突然跳变。请问这种情况下应该怎么优化?是不是应该用requestAnimationFrame?

我来解答 赞 3 收藏
二维码
手机扫码查看
1 条解答
技术宁馨
你这个情况很常见,光绑scroll事件确实会卡顿,特别是低端机上更明显。核心问题有两个:一个是scroll事件触发太频繁,另一个是DOM计算时机不对。

直接给你个优化方案,用requestAnimationFrame配合节流就行,别自己重复造轮子了:

import { useState, useEffect } from 'react';

function ScrollIndicator() {
const [scrollPercent, setScroll] = useState(0);

useEffect(() => {
let ticking = false;

const updateScroll = () => {
const scrollY = window.scrollY;
const height = document.documentElement.scrollHeight - window.innerHeight;
const percent = height > 0 ? (scrollY / height) * 100 : 0;
setScroll(percent);
ticking = false;
};

const handleScroll = () => {
if (!ticking) {
requestAnimationFrame(updateScroll);
ticking = true;
}
};

window.addEventListener('scroll', handleScroll);
// 别忘了resize也要监听,内容变化后高度可能变
window.addEventListener('resize', handleScroll);

return () => {
window.removeEventListener('scroll', handleScroll);
window.removeEventListener('resize', handleScroll);
};
}, []);

return
滚动了{scrollPercent.toFixed(0)}%
;
}

export default ScrollIndicator;


关键点就是那个ticking锁,防止连续触发。另外记得处理下分母为0的情况,不然页面特别短的时候会NaN。如果你项目里用了lodash,直接debounce也行,但raf是最准的,跟浏览器重绘节奏一致。

要是还不放心,插件可以用react-use里的useScrollPercentage,封装好了边界处理。不过你这个需求其实没必要引入依赖,上面改法就够用了。
点赞 4
2026-02-12 22:01