Положение прокрутки скачет, если DOM изменяется, когда упругая прокрутка подпрыгивает

В OS X пользователь может прокрутить окно просмотра, и браузер отскочит страницу.
Как пользователь, мне нравится этот эффект, но он вызывает неприятную ошибку на нашем сайте.

Когда пользователь нажимает большой баннер "Следующая статья" внизу страницы, загружается следующая статья и заменяется большая часть DOM на странице. Когда это происходит, я сбрасываю позицию прокрутки наверх:

window.scrollTo(0, 0);

Это обычно работает нормально. Однако, если пользователю удастся нажать "Следующая статья", когда браузер подпрыгивает на странице из-за упругой прокрутки, scrollTo не работает должным образом. Кажется, что после замены большей части DOM и сброса положения прокрутки, некоторые оставшиеся события от эффекта отскакивания "прибывают" и заставляют прокрутку прыгать на один или два экрана ниже после того, как она была сброшена в ноль.

Как заставить браузер прокручивать до начала и игнорировать оставшиеся подпрыгивающие события?
Это происходит в WebKit.

1 ответ

Решение

Я не смог решить проблему, поэтому в качестве обходного пути я написал функцию, которая возвращает обещание. Это обещание разрешается, когда эластичная прокрутка закончена.

Когда пользователь нажимает "Следующая статья", я загружаю статью, но жду, пока обещание не будет выполнено, прежде чем я выполню операции 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 и анимационный фрейм для rAF polyfill.

Другие вопросы по тегам