В Popper.js виртуальные элементы позволяют создавать всплывающие
элементы (popper) и привязывать их к несуществующим в DOM источникам.
Это особенно важно, когда позиционирование должно быть основано на
координатах, генерируемых динамически, без необходимости создания
реального HTML-узла. Виртуальный элемент представляет собой объект,
который реализует интерфейс
getBoundingClientRect и содержит
координаты, размеры и метаданные, необходимые для расчета позиции
popper.
Основная структура виртуального элемента в Popper.js выглядит следующим образом:
const virtualElement = {
getBoundingClientRect: () => ({
top: 100,
left: 150,
bottom: 140,
right: 190,
width: 40,
height: 40
}),
contextElement: document.body // опционально, используется для ограничения overflow
};
Ключевые моменты:
getBoundingClientRect() — функция,
возвращающая объект с координатами и размерами виртуального элемента.
Это имитация стандартного DOM-метода, используемого браузером для
расчета позиционирования.contextElement — необязательное
свойство, которое позволяет Popper учитывать ограничения overflow при
вычислении позиции.Важное отличие от реального DOM-узла в том, что виртуальный элемент не существует в дереве документа, а его параметры генерируются программно.
Создание popper с виртуальным элементом осуществляется так же, как и с обычным DOM-элементом:
import { createPopper } from '@popperjs/core';
const virtualReference = {
getBoundingClientRect: () => ({
top: 200,
left: 300,
bottom: 240,
right: 340,
width: 40,
height: 40
})
};
const popperElement = document.querySelector('#popper');
createPopper(virtualReference, popperElement, {
placement: 'right',
modifiers: [
{
name: 'offset',
options: {
offset: [0, 8]
}
}
]
});
Особенности работы:
getBoundingClientRect, для расчета позиции popper.document.addEventListener('mousemove', (event) => {
const virtualRef = {
getBoundingClientRect: () => ({
top: event.clientY,
left: event.clientX,
bottom: event.clientY,
right: event.clientX,
width: 0,
height: 0
})
};
popperInstance.state.elements.reference = virtualRef;
popperInstance.update();
});
Виртуальные элементы позволяют создавать popper в точках, которые не привязаны к существующим DOM-узлам, например:
const point = { x: 500, y: 300 };
const virtualPoint = {
getBoundingClientRect: () => ({
top: point.y,
left: point.x,
bottom: point.y,
right: point.x,
width: 0,
height: 0
})
};
createPopper(virtualPoint, popperElement);
contextElement — родительский
контейнер, в котором Popper должен учитывать ограничения.update() у Popper для пересчета позиции.Виртуальные элементы полностью поддерживают стандартные модификаторы Popper.js:
contextElement для ограничения позиции.Пример использования arrow с виртуальным элементом:
createPopper(virtualReference, popperElement, {
placement: 'top',
modifiers: [
{ name: 'arrow', options: { element: '#arrow' } },
{ name: 'offset', options: { offset: [0, 10] } }
]
});
Виртуальные элементы расширяют возможности Popper.js, позволяя создавать всплывающие подсказки, тултипы и меню без необходимости иметь реальный DOM-узел в качестве привязки. Они предоставляют гибкость для динамического позиционирования, взаимодействия с пользовательскими координатами и интеграции с нестандартными интерфейсами.