Установка для Vue 3

Для интеграции 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

Для более удобного интегрирования с 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 };
}

Пример использования в компоненте Vue 3

<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 автоматически удаляет все слушатели при размонтировании компонента.

Рекомендации по структуре проекта

  • Создавать отдельный composable useFloating для повторного использования.
  • Настраивать middleware в зависимости от требуемой логики отображения всплывающих элементов.
  • Использовать реактивные refs для координат x и y, чтобы Vue автоматически обновлял DOM при пересчёте позиции.

Поддержка TypeScript

Для 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

Это обеспечивает модульность, повторное использование кода и простоту поддержки реактивного позиционирования.