0

我在项目开发过程中遇到了一个问题,它与getBoundingClientRect调试期间有和没有预防性断点的值之间的差异有关。为了尽量减少复制,我得到了关注。

const scrollHandler = () => {
  setTimeout(() => {
    const top = document.getElementById('test').getBoundingClientRect().top;
    console.log(top);
  });
};

document.getElementById('viewport').addEventListener('scroll', scrollHandler);

其中viewport只是具有固定高度的可滚动div。的内容viewport足够大,可以触发至少一个滚动事件。我还创建了Plunker 演示。所有的魔法都发生在setTimeout回调内部。

现在是步骤。成功场景。

  1. setTimeout在回调开始时设置断点。
  2. 触发滚动事件。
  3. 让“跨过”来获得top价值。
  4. document.getElementById('test').getBoundingClientRect().top在控制台中执行。
  5. 3和4的结果是一样的

失败的场景。

  1. setTimeout在回调结束时设置断点。
  2. 触发滚动事件。
  3. 获取top变量的值(无需任何操作)。
  4. document.getElementById('test').getBoundingClientRect().top在控制台中执行。
  5. 3和4的结果不一样

为了避免对这个再现产生任何误解,我用上述步骤录制了一个简短的演示电影。

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

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

4

1 回答 1

0

我不确定您在寻找什么,但假设您的滚动动画没有按预期工作。

这里有一个关于限制滚动的提示,这是不正确的。假设您每 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())
于 2018-02-08T16:54:37.827 回答