Логирование state

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


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

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

  • elements – объект с ключами reference, popper и опционально arrow, указывающими на соответствующие DOM-элементы.

    state.elements = {
      reference: HTMLElement,  // элемент, к которому привязан popper
      popper: HTMLElement,     // сам popper
      arrow: HTMLElement | null
    }
  • options – объект с конфигурацией текущего Popper’а, включая placement, modifiers и прочие настройки.

    state.options = {
      placement: 'bottom',
      strategy: 'absolute',
      modifiers: [...]
    }
  • placement – строка, определяющая текущее положение поппера относительно reference. Возможные значения: 'top', 'bottom', 'left', 'right', с вариантами -start и -end.

  • modifiersData – объект, где каждая запись соответствует модификатору и содержит промежуточные результаты его работы. Например, modifiersData.offset хранит текущие смещения x и y.

  • rects – объект с размерами и координатами reference и popper:

    state.rects = {
      reference: DOMRect,
      popper: DOMRect
    }
  • strategy – позиционирование поппера (absolute или fixed).

  • reset – флаг, указывающий, нужно ли сбросить вычисления и повторить их.


Методы логирования

Для анализа поведения поппера используются следующие подходы:

1. Логирование через console.log

Наиболее простой способ — вывод state в консоль из модификатора:

const logStateModifier = {
  name: 'logState',
  enabled: true,
  phase: 'write', // можно использовать 'read', 'main' или 'afterWrite'
  fn({ state }) {
    console.log('Popper state:', state);
  }
};

const popperInstance = Popper.createPopper(referenceEl, popperEl, {
  modifiers: [logStateModifier]
});

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

  • Выводится полный объект state, включая все размеры и промежуточные вычисления.
  • Полезно при диагностике сбоев позиционирования.
  • Для больших объектов лучше использовать console.dir(state, { depth: null }), чтобы развернуть вложенные свойства.

2. Логирование отдельных свойств

Иногда необходимо отследить только конкретные значения, например смещения или текущее размещение:

fn({ state }) {
  const { x, y } = state.modifiersData.popperOffsets || { x: 0, y: 0 };
  console.log(`Popper offsets: x=${x}, y=${y}`);
  console.log(`Current placement: ${state.placement}`);
}

Это снижает шум в консоли и ускоряет поиск ошибок.

3. Отладка через инспектор DOM

Поппер хранит информацию о позиционировании и размерах, что позволяет дополнительно визуализировать state:

  • state.rects.popper – размеры и координаты самого popper’а.
  • state.rects.reference – размеры и координаты reference.
  • Можно временно присвоить их как style для элементов:
Object.assign(popperEl.style, {
  top: `${state.rects.popper.top}px`,
  left: `${state.rects.popper.left}px`
});

Это помогает наглядно увидеть несоответствие вычисленных координат с реальным отображением.


Важные аспекты логирования

  • Фазы модификаторов. Логирование имеет смысл в разных фазах:

    • read – доступно состояние DOM и размеры элементов.
    • main – применяются вычисленные смещения.
    • write – можно изменить DOM после вычислений.
    • afterWrite – финальные координаты и результаты модификаторов.
  • Модификаторы и modifiersData. Все модификаторы, которые изменяют позиционирование, записывают свои результаты в modifiersData. Логирование позволяет убедиться, что смещения и адаптивные изменения работают корректно.

  • Изменение state вручную. В большинстве случаев рекомендуется только читать state. Но если нужно корректировать позиции, это делается через модификатор:

state.modifiersData.offset = { x: 10, y: 20 };
  • Сброс вычислений. Если после изменения данных требуется повторная пересборка позиции, используется:
state.reset = true;

Примеры практического логирования

  1. Отслеживание динамических изменений размеров reference
const logReferenceSize = {
  name: 'logReferenceSize',
  phase: 'read',
  fn({ state }) {
    const { width, height } = state.rects.reference;
    console.log(`Reference size: ${width}x${height}`);
  }
};
  1. Логирование смещений с учетом модификатора offset
const logOffsets = {
  name: 'logOffsets',
  phase: 'main',
  fn({ state }) {
    const offsets = state.modifiersData.offset || { x: 0, y: 0 };
    console.log(`Offsets applied: x=${offsets.x}, y=${offsets.y}`);
  }
};
  1. Отладка placement в сложных условиях
const logPlacement = {
  name: 'logPlacement',
  phase: 'afterWrite',
  fn({ state }) {
    console.log(`Final placement: ${state.placement}`);
  }
};

Выводы по работе с state

  • Объект state предоставляет полный контроль над позиционированием и внутренними вычислениями Popper.js.
  • Логирование отдельных свойств более информативно, чем вывод всего объекта.
  • Использование модификаторов для логирования позволяет интегрировать отладку в рабочий процесс, не изменяя базовую логику приложения.
  • Отслеживание state.rects, modifiersData и placement обеспечивает точную диагностику проблем с позиционированием popper’ов.