В Popper.js для позиционирования всплывающих элементов
(popper) необходим reference — элемент,
относительно которого выполняется вычисление позиции. Обычно reference —
это реальный DOM-элемент. Однако иногда требуется создать
виртуальный reference, который не привязан к
конкретному узлу DOM. Это удобно для кастомных интерфейсов, динамических
анимаций и элементов, которые рендерятся вне DOM или не имеют явного
визуального представления.
Виртуальный reference представляет собой объект с методом
getBoundingClientRect и опциональным свойством
contextElement:
const virtualReference = {
getBoundingClientRect: () => ({
width: 100,
height: 50,
top: 200,
bottom: 250,
left: 300,
right: 400,
}),
contextElement: document.body // необязательный, нужен для scroll context
};
Ключевые моменты:
getBoundingClientRect должен возвращать объект с полями
top, bottom, left,
right, width, height.contextElement определяет контекст для scroll и
overflow. Если не указан, Popper использует document.body
по умолчанию.Popper создается через функцию
createPopper(reference, popper, options). Вместо
DOM-элемента в качестве reference можно передать
виртуальный объект.
import { createPopper } from '@popperjs/core';
const popperElement = document.querySelector('#tooltip');
const virtualReference = {
getBoundingClientRect: () => ({
width: 0,
height: 0,
top: 150,
bottom: 150,
left: 400,
right: 400
})
};
const popperInstance = createPopper(virtualReference, popperElement, {
placement: 'top',
modifiers: [
{
name: 'offset',
options: {
offset: [0, 8]
}
}
]
});
Особенности:
(400, 150).getBoundingClientRect, чтобы перемещать popper без
изменения DOM.Popper.js предоставляет метод update(), который
пересчитывает положение popper относительно reference. Для виртуального
reference это критично, так как координаты могут изменяться в реальном
времени.
let x = 400;
let y = 150;
const virtualReference = {
getBoundingClientRect: () => ({
width: 0,
height: 0,
top: y,
bottom: y,
left: x,
right: x
})
};
setInterval(() => {
x += 1;
y += 1;
popperInstance.update();
}, 16);
Вывод: popper плавно следует за виртуальной точкой, имитируя движение курсора или динамический объект.
Частая практика — привязка всплывающих подсказок к положению курсора. Для этого создается виртуальный reference, обновляемый при движении мыши:
const tooltip = document.querySelector('#tooltip');
const virtualReference = {
getBoundingClientRect: () => ({
width: 0,
height: 0,
top: mouseY,
bottom: mouseY,
left: mouseX,
right: mouseX
})
};
const popperInstance = createPopper(virtualReference, tooltip, {
placement: 'right',
});
let mouseX = 0;
let mouseY = 0;
document.addEventListener('mousemove', (event) => {
mouseX = event.clientX;
mouseY = event.clientY;
popperInstance.update();
});
Особенности такого подхода:
flip, preventOverflow и
offset.Popper учитывает scroll и overflow контейнеры reference через
contextElement. Для виртуальных reference без явного
контекста scroll поведение может отличаться от обычного
DOM-элемента.
const virtualReference = {
getBoundingClientRect: () => ({
width: 50,
height: 50,
top: 100,
bottom: 150,
left: 200,
right: 250
}),
contextElement: document.querySelector('.scroll-container')
};
contextElement задает точку отсчета для всех
вычислений.Виртуальные reference полезны в следующих сценариях:
Использование виртуального reference превращает Popper.js из инструмента для простого DOM-позиционирования в мощный движок для динамических интерфейсов с полной свободой в определении reference.