Статьи

Собственная бесконечная прокрутка с помощью IntersectionObserver API

Эта статья была рецензирована Саймоном Кодрингтоном и Тимом Севериеном . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!

Недавно на веб-платформе появился интересный новый клиентский API-интерфейс JavaScript — IntersectionObserver API .

Этот крошечный, но полезный API-интерфейс предоставляет средства для эффективного мониторинга (наблюдения) видимости определенных элементов DOM, то есть когда они находятся в или вне области просмотра (область просмотра окна браузера или элемента). Определение видимости элемента можно сделать точным, указав долю области элемента, которая пересекает прямоугольник области просмотра.

Некоторые распространенные приложения и варианты использования этой функции:

  • Ленивая загрузка контента
  • Бесконечная прокрутка
  • Видимость рекламы
  • Анимации, запускаемые при прокрутке ( примечание: это не целевой вариант использования. Информация о видимости, сообщаемая API, может поступать с небольшой задержкой, и идеальные данные не гарантируются).

Поддержка браузера

Будучи довольно новым API, его поддержка на момент написания этой статьи все еще ограничена :

  • Chrome Desktop 51
  • Chrome для Android 51
  • Android WebView 51
  • Опера 38
  • Опера для Android 38

Тем не менее, на Github доступен полифилл в стадии разработки (поддержка корневого поля отсутствует), поэтому мы можем начать играть с Intersection Observers прямо сейчас.

В этой статье мы реализуем шаблон UX с бесконечной прокруткой. Мы будем использовать вышеупомянутый полифилл и даже несколько функций ES6 / ES2015, таких как обещания, строки шаблона и функции стрелок.

Бесконечная прокрутка

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

Вот что мы будем строить:

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

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

Настройка страницы

Итак, начнем с HTML. Разметка тела страницы — это просто список:

 <ul class="listview"></ul> 

Обычно этот список должен быть уже заполнен первыми элементами, но для упрощения кода эти элементы будут выбираться из JavaScript, как и последовательные страницы, загружаемые при прокрутке.

Затем мы включаем полифилл. В реальном сценарии мы можем загрузить его только при необходимости. Мы даже проверяем, поддерживается ли API для отображения уведомления на экране:

 <span class="polyfill-notice">The polyfill is in use</span> <script> if (!('IntersectionObserver' in window)) document.body.classList.add('polyfill'); </script> <script src="../intersectionobserver-polyfill.js"></script> 

Что касается CSS, мы используем некоторые правила в основном для настройки макета представления списка и оформления уведомления о поддержке. Поскольку это не является предметом статьи, пожалуйста, обратитесь к таблице стилей для деталей.

Создание сценария

Мы начнем с создания экземпляра объекта IntersectionObserver . Нам нужен только один экземпляр, потому что он будет использоваться для мониторинга всех часовых:

 sentinelObserver = new IntersectionObserver(sentinelListener, {threshold: 1}) 

В объекте конфигурации, переданном во втором аргументе, мы устанавливаем порог видимости (доля видимой части элемента) равным 1 чтобы запускать прослушиватель событий (передаваемый в качестве первого аргумента) только тогда, когда элемент полностью находится в области просмотра. Для целей демонстрации элемент стража обозначен оранжевой рамкой.

Слушатель событий будет выполнять операции, которые мы описали выше. Прежде чем мы рассмотрим его код, давайте представим объект для представления и управления текущим элементом sentinel:

 sentinel = { el: null, set: function(element) { this.el = element; this.el.classList.add('sentinel'); sentinelObserver.observe(this.el); }, unset: function() { if (!this.el) return; sentinelObserver.unobserve(this.el); this.el.classList.remove('sentinel'); this.el = null; } } 

Наиболее важные строки здесь — это когда методы IntersectionObserver observe() и unobserve() для присоединения и отсоединения контролируемого элемента.

Теперь прослушиватель событий может использовать этот вспомогательный объект для удаления текущего стража, установки индикатора загрузки в нижней части списка и загрузки следующей страницы списка с nextPage метода nextPage . Это загружает, отображает и добавляет новые элементы. Он возвращает Обещание, чтобы указать, когда эти операции завершены. В это время мы можем выбрать новый пункт стражи и выключить индикатор загрузки:

 sentinelListener = function(entries) { console.log(entries); sentinel.unset(); listView.classList.add('loading'); nextPage().then(() => { updateSentinel(); listView.classList.remove('loading'); }); } 

Метод updateSentinel выбирает следующего стража, выбирая первый элемент новой загруженной страницы:

 updateSentinel = function() { sentinel.set(listView.children[listView.children.length - pageSize]); } 

Остальная часть кода состоит в основном из реализации функции nextPage . Когда обещание, возвращаемое loadNextPage() (имитирующим сетевой запрос), разрешается, предоставленные объекты элементов отображаются в HTML и добавляются в конец списка.

Вот и все! Вернитесь к демонстрации, чтобы увидеть все фрагменты кода, собранные вместе.

Дальнейшее чтение

Вот несколько ссылок на более подробную документацию, охватывающую как API, так и его обоснование:

Ожидаете ли вы в ближайшее время увидеть больше браузеров, реализующих API IntersectionObserver?