Popper.js предоставляет мощный и гибкий механизм позиционирования всплывающих элементов относительно других элементов DOM. При работе с Vue важно учитывать реактивную природу компонентов, чтобы позиционирование оставалось корректным при изменении состояния приложения.
Для использования Popper.js в Vue-проектах рекомендуется использовать
современный пакет @popperjs/core. Установка производится
через npm или yarn:
npm install @popperjs/core
# или
yarn add @popperjs/core
Импорт в компоненте Vue:
import { createPopper } from '@popperjs/core';
В шаблоне Vue создаются два элемента: reference (относительно которого позиционируется поппер) и popper (сам всплывающий элемент).
<template>
<div ref="referenceElement">Кнопка</div>
<div ref="popperElement" class="popper">Всплывающее окно</div>
</template>
<script>
import { createPopper } from '@popperjs/core';
export default {
mounted() {
this.popperInstance = createPopper(this.$refs.referenceElement, this.$refs.popperElement, {
placement: 'bottom-start',
});
},
beforeUnmount() {
if (this.popperInstance) {
this.popperInstance.destroy();
}
}
}
</script>
Ключевые моменты:
ref используется для получения DOM-элементов в
Vue.placement задаёт начальное положение поппера:
'top', 'bottom', 'left',
'right' и их вариации (-start,
-end).beforeUnmount необходимо уничтожить экземпляр Popper,
чтобы избежать утечек памяти.Vue активно обновляет DOM, поэтому часто требуется обновление позиции поппера после изменения контента или состояния.
methods: {
updatePopper() {
if (this.popperInstance) {
this.popperInstance.update();
}
}
}
Можно вызывать updatePopper после изменения состояния
или контента динамически, либо использовать nextTick для
ожидания завершения рендера:
this.$nextTick(() => {
this.updatePopper();
});
Popper.js поддерживает модификаторы, которые расширяют функциональность:
offset – смещение поппера относительно referenceflip – автоматическое изменение позиции при нехватке
пространстваpreventOverflow – предотвращает выход поппера за
пределы контейнераarrow – позиционирование стрелкиПример:
this.popperInstance = createPopper(this.$refs.referenceElement, this.$refs.popperElement, {
placement: 'bottom',
modifiers: [
{ name: 'offset', options: { offset: [0, 10] } },
{ name: 'flip', options: { fallbackPlacements: ['top', 'right'] } },
{ name: 'preventOverflow', options: { boundary: 'viewport' } },
{ name: 'arrow', options: { element: this.$refs.arrowElement } }
],
});
Особенности модификаторов в Vue:
data и пересоздавать Popper при
изменении значений.ref.Если необходимо, чтобы позиция поппера менялась динамически в
зависимости от состояния Vue, можно использовать watch:
watch: {
tooltipVisible(newValue) {
this.$nextTick(() => {
if (newValue) this.popperInstance.update();
});
}
}
Это гарантирует корректное позиционирование при появлении/скрытии элементов.
При анимации появления поппера через <transition>
важно учитывать, что Popper.js рассчитывает позицию только по завершении
рендера элемента. Рекомендуется использовать onAfterEnter
хука transition:
<transition @after-enter="updatePopper">
<div v-if="tooltipVisible" ref="popperElement" class="popper">Всплывающее окно</div>
</transition>
Для крупных проектов с множеством динамических попперов можно создавать экземпляры Popper в момент показа и уничтожать при закрытии:
methods: {
showPopper() {
if (!this.popperInstance) {
this.popperInstance = createPopper(this.$refs.referenceElement, this.$refs.popperElement);
}
},
hidePopper() {
if (this.popperInstance) {
this.popperInstance.destroy();
this.popperInstance = null;
}
}
}
Это экономит ресурсы и предотвращает накопление ненужных экземпляров.
В Vue 3 с Composition API Popper.js интегрируется через
ref и
onMounted/onBeforeUnmount:
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { createPopper } from '@popperjs/core';
export default {
setup() {
const referenceElement = ref(null);
const popperElement = ref(null);
let popperInstance = null;
onMounted(() => {
popperInstance = createPopper(referenceElement.value, popperElement.value, {
placement: 'bottom',
});
});
onBeforeUnmount(() => {
if (popperInstance) popperInstance.destroy();
});
return { referenceElement, popperElement };
}
}
Преимущества Composition API:
При работе с динамическим контентом важно учитывать, что Popper.js
вычисляет размеры и позиции элементов в момент инициализации. Для
корректного позиционирования после изменения контента необходимо
вызывать update() или пересоздавать экземпляр Popper.
watch(content, () => {
this.$nextTick(() => {
if (this.popperInstance) this.popperInstance.update();
});
});
Popper.js в сочетании с Vue обеспечивает гибкое, реактивное и надёжное позиционирование всплывающих элементов, полностью совместимое с компонентной архитектурой. Использование модификаторов, реактивных параметров и жизненного цикла Vue позволяет создавать сложные интерфейсы с минимальными усилиями.