Фаза read

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

Цель фазы read

Основная задача фазы read — собрать сырые данные о положении и размерах элементов, которые будут использоваться в фазах beforeWrite, compute, write и других. Эти данные включают:

  • Размеры reference элемента (width, height)
  • Позицию reference элемента относительно viewport и scroll container
  • Размеры popper элемента
  • Параметры окна и scroll контейнеров
  • Стили, влияющие на размеры и видимость, например, display, transform, margin, padding, border.

Структура данных

Результатом работы фазы read является объект rects, который содержит:

rects: {
  reference: { width, height, top, left, right, bottom },
  popper: { width, height, top, left, right, bottom }
}
  • reference — информация о reference элементе.
  • popper — информация о popper элементе перед вычислением финальной позиции.

Каждое поле содержит точные численные значения в пикселях, с учётом текущего scroll и transform.

Модификаторы и фаза read

Модификаторы, которые работают на этой фазе, чаще всего не изменяют DOM, а только считывают данные. Примеры таких модификаторов:

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

Важно отметить, что модификаторы могут взаимодействовать друг с другом, используя объект state, который передается во все фазы. В state содержится:

state = {
  elements: {
    reference: HTMLElement,
    popper: HTMLElement
  },
  rects: {
    reference: DOMRect,
    popper: DOMRect
  },
  modifiersData: {},
  options: {},
  placement: 'bottom'
}

Производительность и оптимизация

Фаза read — критический участок с точки зрения производительности, так как чтение layout свойств DOM вызывает reflow. В больших приложениях с множеством попперов важно минимизировать лишние вызовы:

  • Чтение нескольких свойств за один проход через getBoundingClientRect() или offsetWidth/offsetHeight.
  • Кэширование размеров элементов между ререндерингами, если они не изменились.
  • Избегание модификаторов, которые инициируют повторные чтения в одной фазе.

Пример реализации модификатора на фазе read

const customReadModifier = {
  name: 'customRead',
  phase: 'read',
  fn({ state }) {
    const referenceRect = state.elements.reference.getBoundingClientRect();
    const popperRect = state.elements.popper.getBoundingClientRect();

    state.rects.reference = referenceRect;
    state.rects.popper = popperRect;
  }
};

В этом примере модификатор просто считывает размеры и позиции элементов и сохраняет их в объект state.rects для дальнейших фаз. Он не изменяет DOM и не запускает перерисовку, что полностью соответствует назначению фазы read.

Взаимосвязь с другими фазами

После фазы read запускается beforeMain, а затем main и afterMain, где:

  • Данные из read используются для вычисления смещений и окончательной позиции.
  • Любые корректировки размеров или placement зависят от точности данных, собранных на этой фазе.
  • Ошибки на этапе read приводят к неправильному позиционированию, даже если все последующие модификаторы настроены правильно.

Ключевые рекомендации

  • Всегда обеспечивать точное считывание всех элементов, участвующих в позиционировании.
  • Использовать getBoundingClientRect() для корректного учета трансформаций и scroll.
  • Избегать лишних вычислений на этой фазе, так как они напрямую влияют на производительность.

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