Условия для обновления

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

Автоматическое обновление

Popper.js по умолчанию обеспечивает автоматическое отслеживание изменений, влияющих на положение поппера. К таким изменениям относятся:

  • Изменение размеров окна (window.resize).
  • Прокрутка страницы (scroll события на родительских контейнерах и окне).
  • Изменение размеров таргета или поппера (например, изменение текста или стилей через CSS).

Popper.js использует MutationObserver и ResizeObserver для слежения за динамическими изменениями DOM, что позволяет корректно вычислять позицию даже при сложных сценариях.

Ручное обновление

Для более тонкого контроля существует метод update(), который можно вызвать явно:

popperInstance.update();

Вызов этого метода инициирует полный перерасчет позиции поппера. Он полезен, если изменения происходят вне стандартных событий отслеживания Popper.js, например:

  • Динамическая подгрузка контента в поппере.
  • Программное изменение размеров таргета через JavaScript.
  • Анимации, изменяющие размеры элементов.

Метод update() возвращает промис, который разрешается после завершения всех вычислений, что позволяет синхронизировать действия с новой позицией поппера.

Периодические обновления

В некоторых случаях требуется регулярное обновление позиции. Для этого используется метод scheduleUpdate():

popperInstance.scheduleUpdate();

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

События обновления

Popper.js предоставляет события жизненного цикла, которые позволяют реагировать на изменения позиции:

  • onFirstUpdate — вызывается при первой инициализации позиции.
  • Модификаторы могут подписываться на изменения через effect функции, выполняемые при каждом обновлении.

Пример модификатора для логирования позиции:

const logPositionModifier = {
  name: 'logPosition',
  enabled: true,
  phase: 'afterWrite',
  fn({ state }) {
    console.log('Popper position:', state.styles.popper);
  }
};

Модификатор срабатывает каждый раз после перерасчета позиции, что дает возможность отслеживать динамику перемещений поппера.

Условия, влияющие на пересчет

Поппер.js обновляет позицию только при соблюдении определенных условий:

  1. Элемент поппера и таргет присутствуют в DOM. Если один из элементов удален, обновления не происходят.

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

  3. Изменение размеров или положения таргета. Любое событие, влияющее на bounding box таргета, вызывает перерасчет.

  4. Динамическая смена стратегии позиционирования. Если стратегия изменяется с absolute на fixed или наоборот, Popper.js выполняет полное обновление.

Управление частотой обновлений

Для оптимизации производительности можно ограничить количество вызовов обновления с помощью debounce или throttle:

const debouncedUpdate = _.debounce(() => popperInstance.update(), 100);
window.addEventListener('resize', debouncedUpdate);

Это особенно важно при работе с тяжелыми DOM-структурами или анимациями, когда множественные пересчеты могут создавать задержки в рендеринге.

Итоговая схема обновления

  1. Popper.js следит за DOM через Observers и события.
  2. При необходимости инициирует update() или scheduleUpdate().
  3. Применяет модификаторы и вычисляет новую позицию.
  4. Срабатывают события модификаторов, позволяя реагировать на новое положение.
  5. Обновленные стили и атрибуты применяются к попперу и таргету.

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