Алгоритм бесконечного скролла для AngularJS

Сам не реализовывал (не было надобности), только отдельные части, но кое-какие идейки имеются.

Основные идеи

Нужно ограничить общее количество элементов, выводимых на странице (допустим, минимальная высота элемента 100 пикселей, максимальная высота экрана — 2000 пикселей, тогда выводить нужно 50 элементов, с запасом). Обновлять выводимые элементы при скролле с использованием throttle.
Если хотим иметь правильный скролл, нужно сверху и снизу добавить два элемента, которые будут динамически растягиваться, эмулируя убираемые элементы с этой стороны.

Детальнее

Изначально нужно загрузить сразу нужное количество (50) элементов. Потом отслеживать скролл (а также поворот устройства и изменение размеров экрана). Реагировать не на все события, а с какой-то минимальной задержкой, для этого использовать, например, мой throttle-сервис для AngularJS (https://blog.bullgare.com/2014/01/throttle-%D1%81%D0%B5%D1%80%D0%B2%D0%B8%D1%81-%D0%B4%D0%BB%D1%8F-angularjs/).

Жёстко заданная высота (100 пикселей)

Когда пришло время обсчитывать, нужно ли менять выводимые элементы (при отложенном скролле), мы смотрим, сколько элементов осталось с нужной стороны и на сколько мы сместились от верха экрана.
Чтобы узнать, на сколько отскроллили по вертикали, я пользуюсь return window.pageYOffset || window.scrollY || docEl.scrollTop || docBody.scrollTop;
Если скроллим вниз, проверяем количество элементов снизу. Если снизу осталось меньше 10 (к примеру) элементов, убираем сверху 10 элементов, добавляем их снизу, увеличиваем высоту верхней «распорки» на 10 * 100 пикселей, уменьшаем высоту нижней «распорки» на те же 1000 пикселей.

Нежёсткая высота

В этом случае придётся обращаться напрямую к DOM, чтобы узнать высоты всех выведенных элементов через document.getElementsByClassName(‘js-top100-photo’); (и сохраним реальные высоты всех элементов в массив). Для этого нужно задать всем элементам класс js-top100-photo.
Далее всё примерно так же, как и в предыдущем случае, только нужно изменять высоты «распорок» не на 10*100, а сложить нужные высоты из массива.
Основная проблема тут будет при повороте устройства (или изменении ширины), когда уже дошли до каких-нибудь 5000 элементов, т.к. высоты при этом должны будут измениться.
По этому поводу есть предложение высоты «распорок» не пересчитывать, а в массиве высот изменить только высоты элементов, которые сейчас выводятся на экране. При дальнейших скроллах в эту сторону потихоньку менять высоты «распорок» на правильные величины, и надеяться, что особых скачков скролла не будет.

Предлагаю высказывать в комментариях, если есть идеи, как можно этот алгоритм улучшить. А я статью обновлю.

В конце, как всегда, ссылки:
как я реализовывал длинный список фото (без удаления верхних и «распорок») — https://blog.bullgare.com/2013/10/%D0%BF%D0%BE%D0%B4%D0%B3%D1%80%D1%83%D0%B7%D0%BA%D0%B0-%D0%BD%D0%BE%D0%B2%D1%8B%D1%85-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%BF%D1%80%D0%B8-%D1%81%D0%BA%D1%80%D0%BE%D0%BB%D0%BB%D0%B5-%D0%B2-angularj,
реализация большой таблицы — http://gdepourtales.github.io/ng-cells/,
простенький бесконечный скролл от одного из создателей AngularJS — http://jsfiddle.net/vojtajina/U7Bz9/,
тут обещают директиву бесконечного скролла (сам пока не смотрел) — http://binarymuse.github.io/ngInfiniteScroll/,
тут тоже что-то похожее — https://github.com/sparkalow/angular-infinite-scroll.

One Response so far.

  1. bullgare:
    На эту тему, оказывается, есть познавательный перевод на хабре — http://habrahabr.ru/post/204350/

    Но у меня в Google Chrome 31.0.1650.63 при скролле около 80000px сверху всё начало выглядеть вот так — http://grab.by/tkDE . И лоадер появляется в странном месте.
    Но в целом сохранять Dom-элементы в памяти неправильно, т.к. приводит в итоге к такому графику использования памяти — http://grab.by/tkDM. Хотя через какое-то время память, видимо, чистится, т.к. график потом опускается.

LEAVE A COMMENT