Modifiers data

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


Структура модификатора

Каждый модификатор обычно включает следующие поля:

  • name — уникальное имя модификатора. Используется для идентификации и управления порядком исполнения.
  • enabled — логическое значение (true или false), определяющее, активен ли модификатор.
  • phase — стадия, на которой модификатор выполняется. В Popper.js выделяются фазы: beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite.
  • requires — массив имён других модификаторов, которые должны выполниться до текущего.
  • fn — функция модификатора, которая принимает объект data и возвращает его модифицированным.
  • options — объект с дополнительными настройками модификатора.

Пример базового модификатора:

const exampleModifier = {
  name: 'example',
  enabled: true,
  phase: 'main',
  fn({ state, options, name }) {
    // state содержит текущие вычисленные данные
    // options — пользовательские настройки
    console.log(`Модификатор ${name} выполняется с опциями`, options);
  },
  options: {
    offset: 10
  }
};

Объект state и data в модификаторах

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

Основные свойства state:

  • elements — DOM-элементы: { reference, popper }.
  • rects — размеры и координаты элементов: { reference: DOMRect, popper: DOMRect }.
  • modifiersData — объект, в котором хранятся результаты всех модификаторов. Ключи — имена модификаторов, значения — их данные.
  • styles — объект со стилями, применяемыми к попперу.
  • attributes — объект с атрибутами для применения к элементу.
  • reset — флаг, который может инициировать повторный расчёт позиции.

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

const offsetModifier = {
  name: 'offset',
  enabled: true,
  phase: 'main',
  fn({ state, options }) {
    const offsetValue = options.offset || 0;
    const data = state.modifiersData['offset'] || {};
    data.x = state.rects.popper.width + offsetValue;
    data.y = state.rects.popper.height + offsetValue;
    state.modifiersData['offset'] = data;
  },
  options: {
    offset: 10
  }
};

Поток данных между модификаторами

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

Пример:

  1. Модификатор flip использует размеры и позиции поппера для определения, нужно ли перевернуть позицию.
  2. Модификатор offset добавляет смещение к координатам.
  3. Модификатор applyStyles читает modifiersData и применяет вычисленные координаты к элементу через CSS.

Такое разделение логики позволяет строить цепочки модификаторов, где каждый отвечает за отдельный аспект поведения поппера.


Использование options в модификаторах

Опции модификатора задают его поведение. Они могут быть любыми и доступны в fn через объект options.

Пример модификатора с настраиваемыми опциями:

const shiftModifier = {
  name: 'shift',
  enabled: true,
  phase: 'main',
  fn({ state, options }) {
    const shiftX = options.shiftX || 0;
    const shiftY = options.shiftY || 0;
    state.modifiersData['shift'] = {
      x: shiftX,
      y: shiftY
    };
  },
  options: {
    shiftX: 5,
    shiftY: 10
  }
};

state.modifiersData['shift'] теперь доступен другим модификаторам, что позволяет учитывать смещение в итоговой позиции поппера.


Доступ к данным других модификаторов

Чтобы один модификатор корректно работал с результатами другого, используется свойство requires:

const dependentModifier = {
  name: 'dependent',
  enabled: true,
  phase: 'main',
  requires: ['offset'],
  fn({ state }) {
    const offsetData = state.modifiersData['offset'];
    console.log('Используем данные offset:', offsetData);
  }
};

Это гарантирует, что offset будет выполнен до dependent, и его данные будут доступны для использования.


Ключевые моменты при работе с modifiersData

  • Все вычисленные данные модификатора сохраняются в state.modifiersData под именем модификатора.
  • Модификаторы могут изменять state.rects и state.styles, что напрямую влияет на позицию и внешний вид поппера.
  • Фаза выполнения модификатора определяет момент применения изменений — до расчёта, во время основного вычисления, или после применения стилей.
  • options позволяют гибко настраивать поведение без изменения функции fn.
  • Цепочка модификаторов должна быть логически последовательной, чтобы данные одного модификатора корректно использовались другими.

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