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

时间:2014-05-08 16:26:54

标签: javascript macos webkit scroll browser-bugs

在OS X上,用户可以滚动浏览视口,浏览器将弹出页面 作为用户,我喜欢这种效果,但它会在我们的网站上造成一个不幸的错误。

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

window.scrollTo(0, 0);

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

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

1 个答案:

答案 0 :(得分:0)

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

当用户点击“下一篇文章”时,我加载了文章,但是在执行DOM操作并调用scrollTo之前,我等到promise得到解决。这对我很有用。

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。