useFloating в Vue

useFloating — это хук из библиотеки Floating UI, предназначенный для динамического позиционирования всплывающих элементов относительно якоря. В контексте Vue он позволяет легко интегрировать всплывающие панели, тултипы, меню и модальные окна, сохраняя правильное позиционирование при изменении размеров экрана или прокрутке.

Импорт и базовая инициализация

Для начала нужно подключить хук и необходимые вспомогательные функции:

import { useFloating, offset, flip, shift, autoUpdate } from '@floating-ui/vue';
import { ref } from 'vue';

Создание реактивных ссылок на элементы якоря и всплывающего блока:

const reference = ref(null); // элемент, относительно которого позиционируется
const floating = ref(null);   // всплывающий элемент

Инициализация useFloating с базовыми настройками:

const { x, y, strategy, update, middlewareData } = useFloating(reference, floating, {
  placement: 'bottom-start',
  middleware: [offset(8), flip(), shift()],
  whileElementsMounted: autoUpdate
});

Ключевые параметры:

  • placement — начальное положение всплывающего элемента (например, top, bottom-start).
  • middleware — массив функций для обработки позиционирования (offset, flip, shift и другие).
  • whileElementsMounted — функция для автоматического обновления позиции при изменении DOM или скролла.

Работа с middleware

Middleware позволяют управлять поведением всплывающего элемента:

  • offset(value) — задаёт смещение относительно якоря, может быть числом или функцией.
  • flip() — автоматически переворачивает всплывающее окно при недостатке места.
  • shift() — смещает элемент, чтобы он не выходил за границы видимой области.
  • arrow({ element }) — выравнивает стрелку всплывающего блока к якорю.
  • size() — динамически меняет размер всплывающего элемента в зависимости от доступного пространства.

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

import { arrow } from '@floating-ui/vue';

const arrowRef = ref(null);

const { x, y, middlewareData } = useFloating(reference, floating, {
  placement: 'top',
  middleware: [offset(10), flip(), shift(), arrow({ element: arrowRef })]
});

Реактивное позиционирование

x и y — это реактивные значения, которые напрямую привязываются к стилям всплывающего элемента:

<template>
  <div ref="reference">Кнопка</div>
  <div ref="floating" :style="{ position: strategy, top: `${y}px`, left: `${x}px` }">
    Всплывающее окно
    <div ref="arrowRef" class="arrow"></div>
  </div>
</template>

strategy обычно принимает значения absolute или fixed, влияя на контекст позиционирования. Использование autoUpdate обеспечивает автоматическое пересчитывание координат при скролле, изменении размеров окна или элемента.

Управление обновлением позиции вручную

Иногда требуется вручную обновлять позицию, например, после анимации или динамического изменения контента:

const handleResize = () => {
  update(); // пересчёт позиции
};

window.addEventListener('resize', handleResize);

Интеграция с событиями

Можно комбинировать useFloating с событиями Vue для управления видимостью всплывающих элементов:

<template>
  <button ref="reference" @mouseenter="open = true" @mouseleave="open = false">
    Навести
  </button>
  <div v-if="open" ref="floating" :style="{ position: strategy, top: `${y}px`, left: `${x}px` }">
    Тултип
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useFloating, offset, flip, shift, autoUpdate } from '@floating-ui/vue';

const reference = ref(null);
const floating = ref(null);
const open = ref(false);

const { x, y, strategy } = useFloating(reference, floating, {
  placement: 'top',
  middleware: [offset(5), flip(), shift()],
  whileElementsMounted: autoUpdate
});
</script>

Расширенные возможности

useFloating поддерживает комбинированное использование нескольких middleware и динамическое изменение placement в зависимости от состояния:

  • Динамический выбор позиции: можно вычислять оптимальное placement на лету.
  • Адаптация под мобильные устройства: через middleware shift и flip всплывающий элемент остаётся видимым на небольших экранах.
  • Анимации и переходы: координаты x и y можно использовать с CSS-переходами или Vue Transition для плавного появления.

Рекомендации по производительности

  • Использовать autoUpdate только при активном всплывающем элементе.
  • Минимизировать количество middleware при сложных интерфейсах.
  • Избегать тяжелых вычислений внутри middleware, чтобы не блокировать рендер.

useFloating в Vue предоставляет гибкий и мощный инструмент для реализации адаптивных всплывающих интерфейсов, позволяя контролировать позиционирование, динамически реагировать на изменения и интегрироваться с реактивной системой Vue.