Для интеграции Floating UI в проект на Vue 3 используется современный подход через npm или yarn. Библиотека предоставляет низкоуровневый API для позиционирования всплывающих элементов относительно целевых элементов DOM с учётом границ, перекрытий и смещений.
В корневой директории проекта выполняется команда для установки основной библиотеки:
npm install @floating-ui/dom
или через yarn:
yarn add @floating-ui/dom
@floating-ui/dom— это основной пакет для работы с Floating UI на чистом JavaScript и в Vue, он содержит все необходимые утилиты для расчёта позиции, смещения и адаптивного размещения всплывающих элементов.
Для более удобного интегрирования с Vue 3 можно использовать композиционные функции и реактивные свойства. В официальной документации рекомендуется создать собственный composable:
// composables/useFloating.js
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { computePosition, offset, flip, shift } from '@floating-ui/dom';
export function useFloating(referenceEl, floatingEl, options = {}) {
const x = ref(0);
const y = ref(0);
const strategy = options.strategy || 'absolute';
const updatePosition = async () => {
if (referenceEl.value && floatingEl.value) {
const { x: computedX, y: computedY } = await computePosition(
referenceEl.value,
floatingEl.value,
{
middleware: [
offset(options.offset || 8),
flip(),
shift({ padding: 5 })
],
strategy
}
);
x.value = computedX;
y.value = computedY;
}
};
onMounted(() => {
updatePosition();
window.addEventListener('resize', updatePosition);
window.addEventListener('scroll', updatePosition, true);
});
onBeforeUnmount(() => {
window.removeEventListener('resize', updatePosition);
window.removeEventListener('scroll', updatePosition, true);
});
return { x, y, updatePosition };
}
<template>
<div ref="reference" class="button">
Нажми меня
</div>
<div
ref="floating"
class="tooltip"
:style="{ left: x + 'px', top: y + 'px', position: 'absolute' }"
>
Всплывающая подсказка
</div>
</template>
<script setup>
import { ref } from 'vue';
import { useFloating } from '@/composables/useFloating';
const reference = ref(null);
const floating = ref(null);
const { x, y, updatePosition } = useFloating(reference, floating, {
offset: 10
});
</script>
<style scoped>
.button {
display: inline-block;
padding: 10px 20px;
background: #1976d2;
color: white;
cursor: pointer;
}
.tooltip {
padding: 8px 12px;
background: black;
color: white;
border-radius: 4px;
white-space: nowrap;
}
</style>
В этом примере создаётся реактивное позиционирование всплывающего элемента относительно кнопки. Используются middleware offset, flip и shift для корректного размещения с учётом ограничений экрана и возможных перекрытий.
Floating UI позволяет использовать autoUpdate для автоматического пересчёта позиции при изменении размера или прокрутке:
import { autoUpdate } from '@floating-ui/dom';
onMounted(() => {
const cleanup = autoUpdate(reference.value, floating.value, updatePosition);
onBeforeUnmount(cleanup);
});
autoUpdate упрощает ручное добавление слушателей
событий.cleanup автоматически удаляет все
слушатели при размонтировании компонента.useFloating для
повторного использования.x и
y, чтобы Vue автоматически обновлял DOM при пересчёте
позиции.Для TypeScript рекомендуется явно типизировать refs и options:
import type { Ref } from 'vue';
import type { Middleware, Placement } from '@floating-ui/dom';
interface FloatingOptions {
offset?: number;
placement?: Placement;
strategy?: 'absolute' | 'fixed';
middleware?: Middleware[];
}
export function useFloating(
referenceEl: Ref<HTMLElement | null>,
floatingEl: Ref<HTMLElement | null>,
options: FloatingOptions = {}
) {
// реализация аналогична JS версии
}
Такой подход позволяет использовать Floating UI максимально безопасно и с полной поддержкой автодополнения в редакторах.
После установки проекта структура с Floating UI в Vue 3 выглядит следующим образом:
src/
├─ composables/
│ └─ useFloating.js
├─ components/
│ └─ Tooltip.vue
└─ main.js
node_modules/
└─ @floating-ui/dom
package.json
Это обеспечивает модульность, повторное использование кода и простоту поддержки реактивного позиционирования.