Структура state

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


Основные свойства объекта state

Объект state состоит из нескольких ключевых разделов:

1. elements

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

2. options

state.options = {
  placement: 'top' | 'bottom' | 'left' | 'right' | 'auto',
  strategy: 'absolute' | 'fixed',
  modifiers: Array<ModifierObject>,
  onFirstUpdate: Function
};
  • placement — начальное предпочтительное положение поппера относительно reference.
  • strategy — стратегия позиционирования (absolute или fixed).
  • modifiers — массив подключенных модификаторов.
  • onFirstUpdate — колбэк, вызываемый после первого обновления позиции.

3. modifiersData

state.modifiersData = {
  [modifierName: string]: any
};

Хранилище данных, передаваемых модификаторам между собой. Каждый модификатор может сохранять здесь промежуточные результаты:

  • Модификатор arrow сохраняет координаты стрелки.
  • Модификатор offset сохраняет смещение по осям.
  • Модификатор preventOverflow содержит данные о корректировке положения.

4. placement

state.placement = 'top' | 'bottom' | 'left' | 'right' | 'auto';

Финальное положение поппера после применения всех модификаторов. Оно может отличаться от начального options.placement, если активны модификаторы flip или preventOverflow.

5. strategy

state.strategy = 'absolute' | 'fixed';

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

6. rects

state.rects = {
  reference: DOMRect,
  popper: DOMRect,
  arrow: DOMRect | null
};

Содержит размеры и координаты элементов в текущем контексте:

  • reference — размеры и положение элемента reference.
  • popper — размеры и положение поппера.
  • arrow — размеры стрелки, если она используется.

7. scrollParents

state.scrollParents = {
  reference: Array<HTMLElement | Window>,
  popper: Array<HTMLElement | Window>
};

Список всех родительских элементов с прокруткой для reference и popper. Используется модификаторами вроде preventOverflow для расчета доступного пространства.


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

Модификаторы в Popper.js получают объект state при каждом обновлении. Ключевые правила работы:

  • Чтение данных — все модификаторы могут читать state.rects, state.placement, state.modifiersData.
  • Запись данных — каждый модификатор может добавлять новые свойства или изменять существующие в state.modifiersData.
  • Изменение положения — модификаторы, такие как flip или offset, корректируют state.placement и state.styles.

Пример использования данных в модификаторе:

const customModifier = {
  name: 'custom',
  phase: 'write',
  fn({ state }) {
    if (state.rects.popper.width < 100) {
      state.styles.popper.left = '10px';
    }
  }
};

Особенности обновления состояния

  1. Инициализацияstate создается с исходными элементами, настройками и пустыми значениями modifiersData.
  2. Измерение — Popper вычисляет размеры элементов и заполняет rects.
  3. Применение модификаторов — каждый модификатор получает state и может изменить modifiersData, styles и attributes.
  4. Финальная позиция — после всех модификаторов state.placement и state.styles.popper отражают итоговое положение.

Практическая структура state

Структура state в реальном объекте может выглядеть так:

{
  elements: {
    reference: <button id="btn">,
    popper: <div id="tooltip">,
    arrow: <div class="arrow">
  },
  options: {
    placement: 'top',
    strategy: 'absolute',
    modifiers: [...],
    onFirstUpdate: fn
  },
  placement: 'bottom',
  strategy: 'absolute',
  modifiersData: {
    arrow: { x: 10, y: 5 },
    offset: [0, 8],
    preventOverflow: { x: 0, y: 0 }
  },
  rects: {
    reference: DOMRect,
    popper: DOMRect,
    arrow: DOMRect
  },
  scrollParents: {
    reference: [<div.scrollable>],
    popper: [window]
  }
}

Ключевые выводы о state

  • state — это единственный источник правды для Popper.js, объединяющий все данные о позиционировании.
  • Модификаторы должны использовать state аккуратно, чтобы не нарушить последовательность обновлений.
  • Правильное понимание state позволяет создавать сложные кастомные решения: динамическое позиционирование, анимации, нестандартные стрелки, адаптивные подсказки.

Объект state — это ядро Popper.js, управляющее всей логикой вычисления положения и взаимодействия между элементами.