Popper.js — это библиотека для управления всплывающими элементами интерфейса, такими как тултипы, выпадающие списки и контекстные меню, с точным позиционированием относительно целевых элементов. Контекстное меню представляет собой специализированный всплывающий блок, который появляется при взаимодействии пользователя, чаще всего при клике правой кнопкой мыши.
Reference Element Элемент, относительно которого будет позиционироваться меню. В случае контекстного меню это может быть весь документ, определённый контейнер или конкретный элемент списка.
Popper Element Само всплывающее меню, которое
появится при событии. Это может быть <div> с классами
и стилями, оформляющими внешний вид меню.
Modifiers Модификаторы позволяют контролировать поведение меню: смещение от элемента, предотвращение выхода за пределы экрана, автоматическое размещение, изменение размеров.
import { createPopper } from '@popperjs/core';
const reference = document.querySelector('#target');
const popper = document.querySelector('#context-menu');
const popperInstance = createPopper(reference, popper, {
placement: 'bottom-start',
modifiers: [
{
name: 'offset',
options: {
offset: [0, 8],
},
},
{
name: 'preventOverflow',
options: {
boundary: 'viewport',
},
},
],
});
placement определяет позицию меню относительно целевого
элемента. В контекстных меню часто используется
bottom-start или right-start.offset задаёт смещение по оси X и Y, чтобы
меню не перекрывало указатель мыши.preventOverflow гарантирует, что меню не
выйдет за пределы видимой области.Контекстное меню обычно открывается на событие
contextmenu, а закрывается при клике вне меню или на
клавишу Escape.
document.addEventListener('contextmenu', (event) => {
event.preventDefault();
popper.style.display = 'block';
popperInstance.setOptions({
modifiers: [
{
name: 'eventListeners',
enabled: true,
},
],
});
popperInstance.update();
popperInstance.state.elements.reference = {
getBoundingClientRect: () => ({
width: 0,
height: 0,
top: event.clientY,
bottom: event.clientY,
left: event.clientX,
right: event.clientX,
}),
clientWidth: 0,
clientHeight: 0,
};
});
document.addEventListener('click', () => {
popper.style.display = 'none';
});
getBoundingClientRect, чтобы Popper мог
позиционировать меню прямо под курсором.eventListeners
необходимо для корректной работы динамического позиционирования.Для сложных интерфейсов часто требуется динамическое размещение меню, например, чтобы оно всегда оставалось в видимой области, даже если курсор находится у края экрана.
const dynamicPopper = createPopper(reference, popper, {
placement: 'auto',
modifiers: [
{
name: 'flip',
options: {
fallbackPlacements: ['top', 'right', 'left', 'bottom'],
},
},
{
name: 'preventOverflow',
options: {
mainAxis: true,
altAxis: true,
tether: false,
},
},
],
});
flip позволяет Popper автоматически
изменять позицию меню при недостатке места.preventOverflow с параметрами mainAxis и
altAxis контролирует обе оси и предотвращает выход меню за
экран.Для плавного UX контекстное меню часто анимируют с помощью CSS переходов, интегрируя их с Popper.js без влияния на вычисления позиции:
#context-menu {
opacity: 0;
transform: scale(0.95);
transition: opacity 0.15s ease, transform 0.15s ease;
}
#context-menu.show {
opacity: 1;
transform: scale(1);
}
document.addEventListener('contextmenu', (event) => {
event.preventDefault();
popper.classList.add('show');
});
document.addEventListener('click', () => {
popper.classList.remove('show');
});
transform: scale() предотвращает дрожание
меню при появлении.Для многоуровневых контекстных меню каждый уровень создаётся как отдельный Popper, позиционирующийся относительно родительского пункта:
const subMenuPopper = createPopper(parentMenuItem, subMenu, {
placement: 'right-start',
modifiers: [
{ name: 'offset', options: { offset: [0, 0] } },
{ name: 'preventOverflow', options: { boundary: 'viewport' } },
],
});
flip и preventOverflow
предотвращают выход вложенных меню за экран.eventListeners, когда меню
скрыто, чтобы не расходовать ресурсы.strategy: 'fixed' для меню, которое должно
оставаться привязанным к позиции курсора при прокрутке страницы.const popperInstance = createPopper(reference, popper, {
strategy: 'fixed',
});
reference при каждом
открытии.Popper.js обеспечивает высокую точность позиционирования контекстных меню и гибкость при создании сложных интерактивных интерфейсов. Использование модификаторов, динамических ссылок на элемент и CSS-анимаций позволяет создавать как простые, так и многоуровневые контекстные меню с плавным и адаптивным поведением.