在限制滚动事件处理期间的getBoundingClientRect

时间:2018-02-08 15:01:39

标签: javascript scroll settimeout getboundingclientrect

我在项目开发过程中遇到了一个问题,它与调试期间有和没有预防性断点的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回调中。

现在的步骤。成功案例。

  1. setTimeout回调的开头设置断点。
  2. 火焰滚动事件。
  3. 制造"跨越"获得top值。
  4. 在控制台中执行document.getElementById('test').getBoundingClientRect().top
  5. 3和4 的结果相同
  6. 失败的情况。

    1. setTimeout回调结束时设置断点。
    2. 火焰滚动事件。
    3. 获取top变量的值(不需要执行任何操作)。
    4. 在控制台中执行document.getElementById('test').getBoundingClientRect().top
    5. 3和4 的结果不一样
    6. 为了避免与此重复发生任何误解,我使用上述步骤录制了short demo movie

      在我的项目中,我在类似的环境中进行计算(限制滚动事件)并得到与预期不符的错误结果。但是当我调试它时,我会得到不同的画面;预防性断点修复了计算。

      是错误还是已知问题?还是我错过了什么?我应该拒绝在这种情况下使用getBoundingClientRect吗?

1 个答案:

答案 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())