Scroll events

В библиотеке Popper.js управление позиционированием всплывающих элементов при прокрутке страницы является ключевым аспектом для создания корректного интерфейса. Когда родительский элемент или окно прокручиваются, положение поппера (tooltip, dropdown, popover) должно динамически пересчитываться, чтобы сохранять правильное выравнивание относительно референтного элемента.

Автоматическое отслеживание прокрутки

Popper.js использует систему event listeners для отслеживания событий scroll и resize. По умолчанию библиотека автоматически подписывается на события, влияющие на позиционирование поппера:

  • Прокрутка ближайших scrollable контейнеров.
  • Прокрутка окна (window).
  • Изменение размера окна.

Это обеспечивает корректное обновление позиции поппера без необходимости вручную вызывать пересчёт.

Пример создания поппера с автоматическим отслеживанием:

import { createPopper } from '@popperjs/core';

const button = document.querySelector('#button');
const tooltip = document.querySelector('#tooltip');

const popperInstance = createPopper(button, tooltip, {
  modifiers: [
    {
      name: 'eventListeners',
      options: {
        scroll: true,
        resize: true,
      },
    },
  ],
});

Здесь modifiers.eventListeners управляет включением и отключением подписок на события прокрутки и изменения размера.

Модификатор eventListeners

Модификатор eventListeners позволяет точно контролировать, какие события должны отслеживаться:

  • scroll — отслеживает прокрутку контейнеров.
  • resize — отслеживает изменение размеров окна.
  • enabled — включение или отключение модификатора целиком.

Использование модификатора позволяет оптимизировать производительность на страницах с большим количеством попперов.

modifiers: [
  {
    name: 'eventListeners',
    enabled: true,
    options: {
      scroll: true,
      resize: false, // отключаем слушатель изменения размера
    },
  },
]

Обновление позиции вручную при скролле

Иногда требуется тонкий контроль за позиционированием при прокрутке, например, при сложной логике отображения. Для этого можно использовать метод update экземпляра Popper:

window.addEventListener('scroll', () => {
  popperInstance.update();
});

В этом случае popper будет пересчитывать своё положение при каждом событии прокрутки, независимо от встроенных слушателей.

Выбор scrollable контейнеров

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

  1. Определяются все родительские элементы с CSS-свойством overflow: auto | scroll | overlay.
  2. Создаётся список элементов для подписки на события scroll.
  3. При прокрутке любого контейнера вызывается пересчёт позиции поппера.

Проблемы с производительностью

Частые события scroll могут создавать нагрузку на браузер. Чтобы минимизировать её, Popper.js использует throttling и debouncing внутри модификатора eventListeners. Это гарантирует, что пересчёт позиции не вызывается чаще, чем необходимо, сохраняя плавность интерфейса.

Для сложных интерфейсов с множеством попперов рекомендуется:

  • Отключать слушатели для невидимых или временно скрытых попперов.
  • Использовать метод destroy при удалении элементов.
  • Ограничивать количество активных popperInstance на странице.
popperInstance.destroy(); // удаляет слушатели scroll и resize

Взаимодействие с другими модификаторами

Scroll events тесно связаны с модификаторами flip, preventOverflow и offset:

  • flip – автоматически изменяет сторону поппера при достижении края видимой области.
  • preventOverflow – предотвращает выход поппера за границы контейнера.
  • offset – корректирует смещение, учитывая прокрутку и позицию референта.

Корректная работа этих модификаторов возможна только при точной обработке событий прокрутки. Поэтому eventListeners.scroll является критически важным для динамических интерфейсов.

Практические советы

  • Для элементов внутри модальных окон, которые сами скроллятся, убедиться, что Popper подписан на правильный контейнер.
  • Если нужно, чтобы поппер оставался на месте при прокрутке, отключить слушатели scroll.
  • Использовать метод forceUpdate() только в случаях, когда нужно мгновенное пересчитывание позиции без ожидания события.

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