Простота использования настроек Intersection Observer API (IOA) позволяет существенно упростить написание кода для слежения за элементами в зоне видимости и расширить возможности использования нативного JavaScript.
В предыдущей статье мы ознакомились с основами использования Intersection Observer API. Теперь давайте остановимся подробнее на некоторых его опциях для настройки «наблюдателя». Мы также рассмотрим два разных подхода для наблюдения сразу за несколькими элементами.
Опции и настройки Intersection Observer API
Интерфейс Intersection Observer API предоставляет возможность применять несколько опций и настроек. Например, имеется возможность передачи массива параметров (все они необязательны) в качестве второго аргумента конструктора new IntersectionObserver():
- root — родительский элемент для наблюдения за целевыми элементами, расположенными внутри него. По умолчанию — это область просмотра, но им также может быть и любой другой прокручиваемый элемент.
- rootMargin — маргины, используемые для корневого элемента при обнаружении пересечения. Этот параметр работает аналогично свойству margin в CSS, и по умолчанию имеет значение 0px 0px 0px 0px. Установка положительного числа приведет к тому, что наблюдаемые элементы будут иметь значение isIntersecting, равное true, прежде чем они появятся в области видимости (или другом родительском элементе — root).
- threshold — параметр Intersection Observer API, отвечающий за то, какая часть элемента должна находиться в области видимости (или в root элементе), чтобы он считаться видимым. Значение 0 (установлено по умолчанию) означает, что учитывается даже один пиксель, значение 1 — что все пиксели элемента должны быть видны. Для срабатывания метода при появлении элемента на 25% достаточно установить пороговое значение в 0,25. Можно передать одно число или массив чисел.
Например, представим, что нам нужно отложить загрузку текста в определенные блоки, когда они находятся на расстоянии 50 пикселей от границы входа в область видимости.
Для удобства чтения давайте также перенесем функцию обратного вызова в ее собственную именованную функцию.
// Ленивая загрузка текста
function loadText (entries, obs) {
entries.forEach(function (entry) {
// Если наблюдаемый элемент находится за пределами зоны видимости, то ничего не происходит
if (!entry.isIntersecting) return;
// Отключаем «наблюдателя»
obs.unobserve(entry.target);
// Выводим в консоль сообщение, когда элемент войдет в зону видимости
console.log('Элемент в зоне видимости');
// Добавляем в него текст
entry.target.textContent += 'Элемент в зоне видимости';
});
}
// Задаем опции для «наблюдателя»
let options = {
rootMargin: '50px'
};
// Создаем новый «наблюдатель»
let observer = new IntersectionObserver(loadText, options); // Указываем элемент для «наблюдения»
let app = document.querySelector('.element');
// Прикрепляем «наблюдателя» к элементу observer.observe(app);
Наблюдение за несколькими элементами
Intersection Observer API позволяет обеспечивать наблюдение сразу за несколькими элементами с запуском одной и той же callback-функции для каждого из них.
При наблюдении за несколькими элементами сразу массив entries может (но не обязательно) содержать несколько элементов.
Если element_1 и element_2 не расположены рядом друг с другом, один может покинуть область просмотра, когда второй еще в нее не вошел. В этой ситуации тот, который из нее выйдет, сохраняется в массиве entries со значением isIntersecting равным false. А второй будет иметь значение true.
// Создаем новый «наблюдатель»
let observer = new IntersectionObserver( function (entries) {
console.log(entries);
entries.forEach(function (entry) {
console.log(entry.target);
console.log(entry.isIntersecting);
});
});
// Указываем элементы для «наблюдения»
let el_1 = document.querySelector('.element_1');
let el_2 = document.querySelector('.element_2');
// Прикрепляем элементы к «наблюдателя» observer.observe(el_1);
observer.observe(el_2);
При этом в entries отображаются только элементы с измененным состоянием. Например, они находятся рядом друг с другом на странице. При этом только один элемент пересекается с границей области видимости. В этом случае только он находился в entries в callback-функции.
Альтернативный шаблон — один наблюдатель на элемент
Подключение нескольких элементов к одному Intersection Observer API может привести к некоторым неудобствам. Это в первую очередь актуально при командной работе над одним проектом.
В качестве альтернативы можно использовать один «наблюдатель» для каждого элемента. При таком подходе полезно использовать именованную функцию обратного вызова и внешнюю переменную для параметров.
Еще одним способом является создание вспомогательной функции, которая создает новый конструктор IntersectionObserver(). Она активирует «наблюдение» за элементом и вернет «наблюдателя» (observer).
В частности, при использовании этого подхода entries всегда будет содержать только один элемент. Для простоты можно применить деструктуризацию и присвоить первый элемент переменной.
Читайте также: Как использовать буфер обмена через navigator.clipboard API.
/**
Создаем intersection observer
elem - элемент для «наблюдения»
callback - callback-функция
options - объект опций, если они необходимы (необязательный параметр)
*/
function createIntersectionObserver (elem, callback, options) {
let observer = new IntersectionObserver(callback, options || {});
observer.observe(elem);
return observer;
}
/**
Выводим в консоль элемент, если он входит в зону видимости
entries - массив «наблюдаемых» элементов
*/
function log (entries) {
let [entry] = entries;
console.log(entries);
console.log(entry.target);
console.log(entry.isIntersecting);
}
// Задаем опции для «наблюдателя»
let options = {
rootMargin: '50px'
};
// Указываем элементы для «наблюдения»
let el_1 = document.querySelector('.element_1');
let el_2 = document.querySelector('.element_2');
/**
Создаем «наблюдателя» для каждого элемента
Для первого указываем опции
*/
createIntersectionObserver(el_1, log, options);
// Второй использует ту же самую callback-функцию, но без опций
createIntersectionObserver(el_2, log);
В свое время этот способ применения Intersection Observer API вызвал многочисленные споры. Однако в результате большинство ведущих разработчиков пришли к следующему выводу.
Несомненно использование большого количества «наблюдателей» с одним элементом и одного «наблюдателя» с несколькими элементами имеет примерно одинаковую эффективность. Поэтому каждый может выбрать для себя тот, который ему нравится больше. Особой разницы в них нет.
Кроссбраузерность Intersection Observer API
Помимо Internet Explorer этот API браузера имеет полную поддержку.