IntersectionObserver появляется в поле зрения

IntersectionObservers сообщают вам, когда наблюдаемый элемент входит или выходит из области просмотра браузера.

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

  • 51
  • 15
  • 55
  • 12.1

Источник

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

Однако этот подход очень медленный, поскольку каждый вызов getBoundingClientRect() заставляет браузер перерисовывать всю страницу и приводит к значительным перебоям в работе вашего веб-сайта. Ситуация становится практически невозможной, когда вы знаете, что ваш сайт загружается внутри iframe, и хотите знать, когда пользователь сможет увидеть элемент. Модель единого источника и браузер не позволят вам получить доступ к каким-либо данным с веб-страницы, содержащей iframe. Это распространенная проблема, например, для рекламы, которая часто загружается с помощью iframe.

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

Видимость iframe

Как создать IntersectionObserver

API довольно небольшой, и его лучше всего описать на примере:

const io = new IntersectionObserver(entries => {
  console.log(entries);
}, {
  /* Using default options. Details below */
});

// Start observing an element
io.observe(element);

// Stop observing an element
// io.unobserve(element);

// Disable entire IntersectionObserver
// io.disconnect();

Используя параметры по умолчанию для IntersectionObserver , ваш обратный вызов будет вызываться как тогда, когда элемент частично попадает в поле зрения, так и когда он полностью покидает область просмотра.

Если вам нужно наблюдать за несколькими элементами, это возможно и рекомендуется наблюдать за несколькими элементами, используя один и тот же экземпляр IntersectionObserver , вызывая метод observe() несколько раз.

Параметр entries передается вашему обратному вызову, который представляет собой массив объектов IntersectionObserverEntry . Каждый такой объект содержит обновленные данные пересечения для одного из наблюдаемых вами элементов.

🔽[IntersectionObserverEntry]
    time: 3893.92
    🔽rootBounds: ClientRect
        bottom: 920
        height: 1024
        left: 0
        right: 1024
        top: 0
        width: 920
    🔽boundingClientRect: ClientRect
    // ...
    🔽intersectionRect: ClientRect
    // ...
    intersectionRatio: 0.54
    🔽target: div#observee
    // ...

rootBounds — это результат вызова getBoundingClientRect() для корневого элемента, который по умолчанию является областью просмотра. boundingClientRect является результатом метода getBoundingClientRect() , вызванного для наблюдаемого элемента. intersectionRect — это пересечение этих двух прямоугольников, которое эффективно сообщает вам , какая часть наблюдаемого элемента видна. intersectionRatio тесно связан с ним и сообщает вам , какая часть элемента видна. Имея в своем распоряжении эту информацию, вы теперь можете реализовать такие функции, как своевременная загрузка ресурсов, прежде чем они станут видимыми на экране. Эффективно.

Коэффициент пересечения.

IntersectionObserver доставляет свои данные асинхронно, и ваш код обратного вызова будет выполняться в основном потоке. Кроме того, в спецификации фактически говорится, что реализации IntersectionObserver должны использовать requestIdleCallback() . Это означает, что вызов предоставленного вами обратного вызова имеет низкий приоритет и будет выполняться браузером во время простоя. Это осознанное дизайнерское решение.

Прокрутка div

Я не большой поклонник прокрутки внутри элемента, но не мне судить, равно как и IntersectionObserver . Объект options принимает root опцию, которая позволяет вам определить альтернативу области просмотра в качестве корневой. Важно помнить, что root должен быть предком всех наблюдаемых элементов.

Пересеките все вещи!

Нет! Плохой разработчик! Это не разумное использование циклов процессора вашего пользователя. Давайте рассмотрим в качестве примера бесконечный скроллер: в этом сценарии определенно желательно добавить датчики в DOM и наблюдать (и перерабатывать!) их. Вам следует добавить индикатор рядом с последним элементом бесконечного скроллера. Когда этот страж появится в поле зрения, вы можете использовать обратный вызов для загрузки данных, создания следующих элементов, присоединения их к DOM и соответствующего изменения положения стража. Если вы правильно перезапустите дозорный, дополнительный вызов observe() не потребуется. IntersectionObserver продолжает работать.

Бесконечный скроллер

Больше обновлений, пожалуйста

Как упоминалось ранее, обратный вызов будет запущен один раз, когда наблюдаемый элемент частично появляется в поле зрения, и еще раз, когда он покидает область просмотра. Таким образом, IntersectionObserver дает вам ответ на вопрос: «Видится ли элемент X?». Однако в некоторых случаях использования этого может быть недостаточно.

Вот тут-то и вступает в игру threshold опция. Это позволяет вам определить массив пороговых значений intersectionRatio . Ваш обратный вызов будет вызываться каждый раз, когда intersectionRatio пересекает одно из этих значений. Значение по умолчанию для threshold[0] , что объясняет поведение по умолчанию. Если мы изменим threshold на [0, 0.25, 0.5, 0.75, 1] ​​, мы будем получать уведомление каждый раз, когда становится видимой дополнительная четверть элемента:

Пороговая анимация.

Есть еще варианты?

На данный момент есть только одна дополнительная опция к перечисленным выше. rootMargin позволяет вам указать поля для корня, что позволяет вам увеличивать или уменьшать область, используемую для пересечений. Эти поля задаются с помощью строки в стиле CSS, типа "10px 20px 30px 40px" , определяющей верхнее, правое, нижнее и левое поля соответственно. Подводя итог, структура параметров IntersectionObserver предлагает следующие параметры:

new IntersectionObserver(entries => {/* … */}, {
  // The root to use for intersection.
  // If not provided, use the top-level document's viewport.
  root: null,
  // Same as margin, can be 1, 2, 3 or 4 components, possibly negative lengths.
  // If an explicit root element is specified, components may be percentages of the
  // root element size.  If no explicit root element is specified, using a
  // percentage is an error.
  rootMargin: "0px",
  // Threshold(s) at which to trigger callback, specified as a ratio, or list of
  // ratios, of (visible area / total area) of the observed element (hence all
  // entries must be in the range [0, 1]).  Callback will be invoked when the
  // visible ratio of the observed element crosses a threshold in the list.
  threshold: [0],
});

<iframe> магия

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

Чем не является IntersectionObserver ?

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

Какой объем работы я могу выполнить при обратном вызове?

Коротко и приятно: если вы потратите слишком много времени на обратный вызов, ваше приложение будет зависать — применяются все распространенные методы.

Иди вперед и пересекай свои элементы

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

Вы можете начать использовать IntersectionObserver прямо сейчас! Расскажите нам, что вы придумали.