React无限滚动组件:offsetHeight+scrollTop≠scrollHeight的异常问题
问题描述
开发React无限滚动组件时,通过offsetHeight + scrollTop == scrollHeight判断是否滚动至底部,仅在125%、100%、75%、67%缩放比例下正常;但在110%、90%、80%等缩放比例时,滚动到底部时offsetHeight + scrollTop的总和始终略小于scrollHeight,导致无法触发后续加载逻辑。
控制台输出示例:
110%缩放时:
690.9090881347656 == 696
694.5454406738281 == 696
695.757568359375 == 696100%缩放时:
694.6666564941406 == 696
695.3333435058594 == 696
696 == 696
ok90%缩放时:
694.0740966796875 == 696
694.8148498535156 == 696
695.5555725097656 == 696
原核心代码:
const handleScroll = async (e) => { const { offsetHeight, scrollTop, scrollHeight } = e.target; console.log(offsetHeight + scrollTop + " == " + scrollHeight); if (offsetHeight + scrollTop == scrollHeight) { console.log("ok"); setStep((prev) => prev + step); fetchData(nowStep + step); } }; return ( <div onScroll={handleScroll} style={{ height: height, overflowY: "scroll", overflowX: "hidden", width: "100%", padding: 0, margin: 0, textAlign: "center", }} > {children} </div> )
问题原因
浏览器缩放时,scrollTop和offsetHeight会因为像素渲染精度产生小数(比如110%缩放时的695.757...),而scrollHeight通常是元素内容的实际高度(多为整数或更精确的整数值)。直接使用严格相等判断,会因为微小的数值差导致条件不成立。
解决方案
放弃严格相等判断,改用容差范围匹配,允许数值存在极小的误差(比如小于1px的差距),或者对数值进行取整处理。以下是两种可行的修改方式:
方式1:使用容差判断(推荐)
判断offsetHeight + scrollTop是否接近scrollHeight,允许1px以内的误差:
const handleScroll = async (e) => { const { offsetHeight, scrollTop, scrollHeight } = e.target; const scrollBottom = offsetHeight + scrollTop; console.log(scrollBottom + " == " + scrollHeight); // 允许1px以内的误差,避免缩放导致的精度问题 if (scrollBottom >= scrollHeight - 1) { console.log("ok"); setStep((prev) => prev + step); fetchData(nowStep + step); } };
方式2:对数值取整后判断
将scrollBottom和scrollHeight都取整后再做相等判断:
const handleScroll = async (e) => { const { offsetHeight, scrollTop, scrollHeight } = e.target; const scrollBottom = Math.round(offsetHeight + scrollTop); const roundedScrollHeight = Math.round(scrollHeight); console.log(scrollBottom + " == " + roundedScrollHeight); if (scrollBottom === roundedScrollHeight) { console.log("ok"); setStep((prev) => prev + step); fetchData(nowStep + step); } };
补充说明
- 容差值可以根据实际场景调整,一般1px足够覆盖浏览器缩放带来的精度误差;
- 也可以使用
Math.abs(scrollBottom - scrollHeight) < 1的方式进行判断,逻辑更直观。
内容的提问来源于stack exchange,提问作者Nguyễn Tuấn Kiệt

