Elements в state

Popper.js управляет позиционированием всплывающих элементов относительно опорных элементов на странице. В основе этого механизма лежит state, объект, содержащий актуальную информацию о позиционировании, размере и состоянии каждого элемента, участвующего в расчётах. Ключевое место в state занимают elements, которые представляют собой ссылки на реальные DOM-узлы.


Структура объекта elements

В state объект elements представлен как объект с двумя основными свойствами:

state.elements = {
  reference: HTMLElement,
  popper: HTMLElement,
  arrow?: HTMLElement
};
  • reference – это элемент, относительно которого позиционируется всплывающий блок. Обычно это кнопка, ссылка или любой интерактивный объект.
  • popper – непосредственно всплывающий элемент, который будет отображаться на странице.
  • arrow – необязательный элемент, который отображает стрелку на поппере и указывает на reference. Если стрелка отсутствует в DOM, это свойство может быть null.

Каждое из этих свойств является живой ссылкой на DOM, что позволяет Popper.js напрямую манипулировать их размерами и положением при каждом обновлении state.


Обновление элементов в state

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

popperInstance.setOptions({
  modifiers: [
    {
      name: 'updateElements',
      enabled: true,
      phase: 'beforeWrite',
      fn({ state }) {
        state.elements.reference = document.querySelector('#newReference');
      }
    }
  ]
});

Важные моменты:

  • Изменение элемента reference автоматически инициирует пересчёт позиции popper.
  • Замена popper позволяет динамически подгружать другой всплывающий элемент.
  • Если изменяется arrow, его положение и ориентация пересчитываются на основе новых размеров popper и reference.

Доступ к элементам внутри модификаторов

Модификаторы Popper.js получают объект state на каждом цикле обновления. Для работы с элементами важно помнить:

modifiers: [
  {
    name: 'exampleModifier',
    enabled: true,
    phase: 'main',
    fn({ state }) {
      const refRect = state.elements.reference.getBoundingClientRect();
      const popperRect = state.elements.popper.getBoundingClientRect();
      
      console.log('Reference ширина:', refRect.width);
      console.log('Popper высота:', popperRect.height);
    }
  }
]
  • getBoundingClientRect() возвращает актуальные размеры и положение элементов на странице.
  • state.elements всегда содержит актуальные DOM-узлы, даже если они были заменены динамически.
  • Можно безопасно обращаться к arrow, проверяя его наличие:
if (state.elements.arrow) {
  const arrowRect = state.elements.arrow.getBoundingClientRect();
}

Работа с элементами в асинхронном контексте

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

if (state.elements.reference && state.elements.popper) {
  popperInstance.update();
}
  • Проверка на существование элементов предотвращает обращения к null.
  • После добавления новых DOM-узлов можно вручную инициировать обновление с помощью popperInstance.update().

Динамическая подстановка элементов

Popper.js позволяет подставлять элементы через функции возвращающие DOM:

const popperInstance = Popper.createPopper(() => document.querySelector('#dynamicRef'), () => document.querySelector('#dynamicPopper'));
  • Используется ленивое вычисление элементов.
  • State автоматически обновляется при каждом цикле расчёта.
  • Позволяет создавать всплывающие элементы, которые подгружаются только при необходимости.

Примеры полезных операций с state.elements

  1. Смена reference:
state.elements.reference = document.getElementById('newButton');
popperInstance.update();
  1. Смена popper:
state.elements.popper = document.getElementById('newTooltip');
popperInstance.update();
  1. Адаптация arrow под размеры popper:
if (state.elements.arrow) {
  const arrowWidth = state.elements.arrow.offsetWidth;
  const popperWidth = state.elements.popper.offsetWidth;
  state.modifiersData.arrow = { offset: (popperWidth - arrowWidth) / 2 };
}

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


Резюме ключевых особенностей elements в state

  • Представляют живые DOM-узлы: reference, popper и опционально arrow.
  • Доступны для модификаторов на всех фазах расчёта.
  • Поддаются динамическому обновлению без пересоздания инстанции.
  • Позволяют безопасно и точно вычислять размеры и позиции элементов.
  • Поддерживают ленивую подстановку через функции для асинхронного контента.

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