Эта статья была рецензирована Саймоном Кодрингтоном и Тимом Севериеном . Спасибо всем рецензентам 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, так и его обоснование:
- Представление IntersectionObserver
- Объяснение наблюдателей за пересечением
- MDN — API IntersectionObserver
Ожидаете ли вы в ближайшее время увидеть больше браузеров, реализующих API IntersectionObserver?