我在项目开发过程中遇到了一个问题,它与调试期间有和没有预防性断点的getBoundingClientRect
值之间的差异有关。为了尽量减少repro,我得到了跟进。
const scrollHandler = () => {
setTimeout(() => {
const top = document.getElementById('test').getBoundingClientRect().top;
console.log(top);
});
};
document.getElementById('viewport').addEventListener('scroll', scrollHandler);
其中viewport
只是具有固定高度的可滚动div。 viewport
的内容足够大,可以触发至少一个滚动事件。我还创建了Plunker demo。所有魔法都发生在setTimeout
回调中。
现在的步骤。成功案例。
setTimeout
回调的开头设置断点。top
值。document.getElementById('test').getBoundingClientRect().top
。失败的情况。
setTimeout
回调结束时设置断点。top
变量的值(不需要执行任何操作)。document.getElementById('test').getBoundingClientRect().top
。为了避免与此重复发生任何误解,我使用上述步骤录制了short demo movie。
在我的项目中,我在类似的环境中进行计算(限制滚动事件)并得到与预期不符的错误结果。但是当我调试它时,我会得到不同的画面;预防性断点修复了计算。
是错误还是已知问题?还是我错过了什么?我应该拒绝在这种情况下使用getBoundingClientRect
吗?
答案 0 :(得分:0)
我不确定你在寻找什么但是假设滚动动画没有按预期工作。
限制滚动here的提示不正确。假设你节流到每30毫秒。如果页面在上一次动画后停止滚动25毫秒,那么在停止滚动之前25毫秒就会停留一个滚动位置。
也许更好的方法就是这个(可以在这个页面的控制台上测试):
var ol = document.querySelectorAll("ol")[2];
window.onscroll = ((lastExecuted)=>{
const expensiveHandler = e => {
lastExecuted=Date.now();
//do some animation maybe with requestAnimationFrame
// it may prevent overloading but could make animation
// glitchy if system is busy
console.log("1:",ol.getBoundingClientRect().top);
};
var timerID
return e=>{
if(Date.now()-lastExecuted>19){
//only animate once every 20 milliseconds
clearTimeout(timerID);
expensiveHandler(e);
}else{
//make sure the last scroll event does the right animation
// delay of 20 milliseconds
console.log("nope")
clearTimeout(timerID);//only the last is needed
timerID=setTimeout(e=>expensiveHandler(e),20);
}
}
})(Date.now())