如果在弹性滚动弹跳时更改 DOM,则滚动位置会跳转

Posted

技术标签:

【中文标题】如果在弹性滚动弹跳时更改 DOM,则滚动位置会跳转【英文标题】:Scroll position jumps if DOM is changed while elastic scroll is bouncing 【发布时间】:2014-06-26 04:14:11 【问题描述】:

在 OS X 上,用户可以滚动查看视口,浏览器会弹回页面。 作为用户,我喜欢这种效果,但它会导致我们网站出现不幸的错误。

当用户点击页面底部的“下一篇”大横幅时,会加载下一篇文章并替换页面上的大部分 DOM。发生这种情况时,我将滚动位置重置为顶部:

window.scrollTo(0, 0);

这通常可以正常工作。但是,如果用户在浏览器因弹性滚动而弹跳页面时点击“下一篇文章”scrollTo 将无法正常工作。似乎在替换了大部分 DOM 并重置滚动位置之后,弹跳效果中的一些剩余事件“到达”并使滚动在 重置为零之后跳到下方一两个屏幕。 p>

如何强制浏览器滚动到开头并忽略剩余的弹跳事件? 这发生在 WebKit 上。

【问题讨论】:

【参考方案1】:

我无法解决这个问题,因此作为一种解决方法,我编写了一个返回承诺的函数。这个承诺在弹性滚动完成后解决。

当用户点击“下一篇文章”时,我会加载文章,但我会等到 promise 解决后再执行 DOM 操作并调用scrollTo。这对我很有效。

function waitForElasticScroll() 

  // If user scrolls part viewport and clicks while elastic scroll
  // has not fully "returned", scroll position will get messed up in Chrome.

  // Our workaround is to wait for elastic scroll to finish before transitioning.
  // rAF calls help avoid unnecessary layout.

  return new Promise(function (resolve) 
    window.requestAnimationFrame(function () 
      var maxScrollY = document.body.scrollHeight - window.innerHeight;

      function isReady() 
        var scrollY = window.scrollY || window.pageYOffset;
        return scrollY <= maxScrollY;
      

      function resolveIfReady() 
        if (isReady()) 
          resolve();
         else 
          window.requestAnimationFrame(resolveIfReady);
        
      

      resolveIfReady();

    );
  );

我将 Bluebird 用于 Promises,animation-frame 用于 rAF polyfill。

【讨论】:

以上是关于如果在弹性滚动弹跳时更改 DOM,则滚动位置会跳转的主要内容,如果未能解决你的问题,请参考以下文章

位置:粘性 - 结合 javascript 高度调整时滚动弹跳

React监听滚动条事件——页面跳转后返回当前滚动条位置

滚动时禁用 UITableView 垂直反弹

分组 TableView,使用自定大小的部分标题,重新加载后,如果我向上滚动,tableview 会跳转

位置:粘性 - 与javascript高度调整结合使用时滚动弹跳

在移动设备上滚动时保持标题位置固定