Фазы работы модификаторов

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


1. Фаза beforeRead

Назначение: подготовка данных перед чтением размеров и позиции элементов.

На этом этапе модификаторы получают доступ к текущему состоянию, но ещё не выполнены вычисления геометрии. Обычно используется для:

  • Сброса предыдущих значений позиции.
  • Подготовки пользовательских данных для последующих фаз.
  • Активации внешних условий, влияющих на чтение DOM.

Модификаторы этой фазы не должны изменять вычисленные размеры, а лишь настраивать состояние.

Пример использования:

const beforeReadModifier = {
  name: 'beforeReadExample',
  phase: 'beforeRead',
  enabled: true,
  fn({ state }) {
    state.attributes.popper = { 'data-before-read': true };
  }
};

2. Фаза read

Назначение: считывание текущих размеров и расположения элементов в DOM.

Модификаторы этой фазы получают актуальные bounding rects целевого элемента (reference) и всплывающего блока (popper) и могут использовать эти данные для дальнейших вычислений. Применяется для:

  • Получения ширины, высоты, координат.
  • Определения видимости или перекрытия элементов.
  • Формирования данных для расчёта смещения и позиционирования.

Важно понимать, что на этом этапе не рекомендуется изменять DOM или размеры элементов — только считывать.

Пример использования:

const readModifier = {
  name: 'readExample',
  phase: 'read',
  enabled: true,
  fn({ state }) {
    state.modifiersData.readExample = {
      width: state.rects.popper.width,
      height: state.rects.popper.height
    };
  }
};

3. Фаза beforeMain

Назначение: подготовка данных перед основной фазой вычислений (main).

На этом этапе модификаторы могут изменять данные, которые будут использоваться для расчёта позиции, но ещё не происходит окончательного изменения позиции поппера. Обычно применяется для:

  • Активации условий смещения.
  • Корректировки параметров с учётом сторонних факторов.
  • Добавления кастомных ограничений или правил.

4. Фаза main

Назначение: основная фаза вычисления позиции и применения изменений.

В этой фазе выполняются ключевые модификаторы, влияющие на позицию поппера, например:

  • offset — смещение относительно целевого элемента.
  • flip — автоматический выбор подходящей стороны.
  • preventOverflow — предотвращение выхода за пределы контейнера.

Особенности:

  • Данные модификаторов могут изменять координаты поппера напрямую.
  • Модификаторы этой фазы являются центральными для позиционирования и часто зависят от результатов предыдущих фаз.

Пример модификатора main:

const mainModifier = {
  name: 'mainExample',
  phase: 'main',
  enabled: true,
  fn({ state }) {
    state.styles.popper.left += 10; // простое смещение
  }
};

5. Фаза afterMain

Назначение: действия после основной фазы расчёта позиции.

Позволяет:

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

6. Фаза beforeWrite

Назначение: подготовка к записи изменений в DOM.

На этом этапе можно:

  • Формировать финальные стили.
  • Подготавливать атрибуты и классы для popper или reference.
  • Рассчитывать анимационные параметры.

7. Фаза write

Назначение: непосредственное применение изменений в DOM.

Модификаторы этой фазы изменяют:

  • CSS-свойства (top, left, transform и др.).
  • Атрибуты элементов.
  • Псевдоэлементы или классы.

Пример применения стилей:

const writeModifier = {
  name: 'writeExample',
  phase: 'write',
  enabled: true,
  fn({ state }) {
    Object.assign(state.elements.popper.style, state.styles.popper);
  }
};

8. Фаза afterWrite

Назначение: завершающие действия после записи изменений.

Применяется для:

  • Очистки временных данных.
  • Выполнения событий или коллбеков.
  • Логирования или интеграции с внешними библиотеками.

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

  • Порядок выполнения фаз строго фиксирован: beforeRead → read → beforeMain → main → afterMain → beforeWrite → write → afterWrite.
  • Каждая фаза имеет своё предназначение: попытка выполнить всё сразу в одной фазе приводит к ошибкам и некорректному позиционированию.
  • Модификаторы могут использовать данные предыдущих фаз, но должны быть аккуратны с изменением состояния до фазы write.
  • Производительность: чем меньше операций в фазах read и main, тем быстрее рендер поппера, особенно при сложной верстке или анимации.

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