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

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

Экземпляр Popper создаётся через конструктор createPopper(reference, popper, options), где:

  • reference — элемент, относительно которого будет позиционироваться всплывающее окно.
  • popper — сам всплывающий элемент.
  • options — объект с настройками поведения, позиционирования и модификаторами.

Пример базового создания:

import { createPopper } from '@popperjs/core';

const referenceElement = document.querySelector('#button');
const popperElement = document.querySelector('#tooltip');

const popperInstance = createPopper(referenceElement, popperElement, {
  placement: 'top',
  modifiers: [
    {
      name: 'offset',
      options: {
        offset: [0, 8],
      },
    },
  ],
});

Переназначение reference и popper

Одним из ключевых приёмов переиспользования является динамическая смена reference или popper элементов без создания нового экземпляра Popper. В Popper.js это достигается с помощью метода setOptions:

popperInstance.setOptions({
  ...popperInstance.state.options,
  reference: newReferenceElement,
  modifiers: [
    {
      name: 'offset',
      options: { offset: [0, 12] },
    },
  ],
});

После изменения опций необходимо вызвать update(), чтобы пересчитать позицию:

popperInstance.update();

Таким образом, один экземпляр Popper можно использовать для разных кнопок или элементов, меняя только привязку и настройки.

Управление жизненным циклом

Для эффективного переиспользования важно контролировать жизненный цикл экземпляра:

  • Инициализация — создание через createPopper.
  • Обновление опций — с помощью setOptions и update.
  • Скрытие и показ — управление видимостью через CSS или модификатор eventListeners.
  • Удаление — вызов destroy(), если экземпляр больше не нужен:
popperInstance.destroy();

Не рекомендуется создавать новый экземпляр для каждого элемента, если их можно обслуживать одним объектом. Это снижает нагрузку на DOM и улучшает производительность, особенно при множественных динамических тултипах.

Модификаторы для переиспользуемых экземпляров

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

  1. offset — позволяет задавать смещение popper относительно reference, которое может меняться в зависимости от контекста.
  2. preventOverflow — автоматически корректирует позицию, если всплывающее окно выходит за границы контейнера.
  3. flip — изменяет положение popper при недостатке пространства.
  4. eventListeners — позволяет включать или отключать слежение за событиями scroll и resize без уничтожения экземпляра.

Пример динамической настройки модификаторов:

popperInstance.setOptions({
  modifiers: [
    { name: 'offset', options: { offset: [0, dynamicOffset] } },
    { name: 'flip', options: { fallbackPlacements: ['top', 'right'] } },
  ],
});
popperInstance.update();

Паттерн единственного экземпляра для списка элементов

В интерфейсах с множеством элементов удобно использовать один Popper для всех элементов списка, переназначая reference при наведении:

const popperElement = document.querySelector('#tooltip');
let popperInstance = null;

document.querySelectorAll('.list-item').forEach(item => {
  item.addEventListener('mouseenter', () => {
    if (!popperInstance) {
      popperInstance = createPopper(item, popperElement, { placement: 'top' });
    } else {
      popperInstance.setOptions({ reference: item });
      popperInstance.update();
    }
    popperElement.style.display = 'block';
  });

  item.addEventListener('mouseleave', () => {
    popperElement.style.display = 'none';
  });
});

Этот подход минимизирует создание новых объектов и поддерживает высокую отзывчивость интерфейса.

Динамическая смена контента

При переиспользовании одного popper часто требуется менять контент всплывающего окна:

function showTooltip(reference, content) {
  popperElement.textContent = content;
  popperInstance.setOptions({ reference });
  popperInstance.update();
  popperElement.style.display = 'block';
}

Такой метод позволяет использовать единый DOM-элемент для всех подсказок и полностью контролировать их содержание и позицию через один экземпляр Popper.

Рекомендации по оптимизации

  • Один экземпляр на группу элементов вместо отдельного для каждого.
  • Минимизация модификаторов: используйте только необходимые для конкретного случая.
  • Контроль обновлений: вызов update() только при изменении reference или модификаторов.
  • Очистка событий: если popper временно не используется, отключайте eventListeners для экономии ресурсов.

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