В библиотеке Floating UI жизненный цикл элементов управляется через
создание, обновление и уничтожение плавающих компонентов. Основной
объект, через который происходит управление позиционированием, — это
floating instance, создаваемый функцией
computePosition или через хуки, предоставляемые библиотекой
(useFloating в React, createFloating в vanilla
JS).
Жизненный цикл включает три ключевых этапа:
Каждый этап тесно связан с middleware, которые позволяют модифицировать поведение позиционирования: смещение, ограничение в пределах viewport, автоматическое выравнивание и пр.
Функция computePosition(reference, floating, options)
возвращает объект с координатами x и y,
которые затем можно применить к стилям элемента.
import { computePosition, offset, flip } from '@floating-ui/dom';
const reference = document.querySelector('#button');
const floating = document.querySelector('#tooltip');
computePosition(reference, floating, {
middleware: [offset(10), flip()],
}).then(({ x, y }) => {
Object.assign(floating.style, {
left: `${x}px`,
top: `${y}px`,
});
});
Ключевые моменты:
offset, flip, shift,
autoPlacement и др.).Инициализация — это момент, когда определяется начальная позиция, но она статична, если не подключить механизмы обновления.
Floating UI предоставляет два способа поддерживать актуальное
позиционирование: автоматическое обновление через
autoUpdate и ручное обновление через повторный
вызов computePosition.
Функция autoUpdate(reference, floating, updateCallback)
устанавливает слушатели событий, которые отслеживают:
ResizeObserver).scroll).MutationObserver).import { autoUpdate, computePosition } from '@floating-ui/dom';
const cleanup = autoUpdate(reference, floating, () => {
computePosition(reference, floating, { middleware: [offset(8), flip()] }).then(({ x, y }) => {
Object.assign(floating.style, { left: `${x}px`, top: `${y}px` });
});
});
// Для остановки обновлений
cleanup();
Особенности:
autoUpdate возвращает функцию очистки, которая снимает
все слушатели.Иногда требуется обновление позиции в специфических случаях: при
изменении состояния приложения, контента или смене ориентации. В таких
случаях вызывается computePosition напрямую.
button.addEventListener('click', () => {
computePosition(reference, floating, { middleware: [offset(10)] }).then(({ x, y }) => {
Object.assign(floating.style, { left: `${x}px`, top: `${y}px` });
});
});
Ручное обновление даёт полный контроль над логикой обновления, но требует самостоятельного управления событиями, если позиция должна оставаться динамичной.
Middleware напрямую влияют на жизненный цикл и динамическое обновление:
Каждый middleware вызывается при каждом обновлении позиции. Важно
учитывать порядок: offset всегда применяется после
flip, чтобы смещение корректно учитывалось после выбора
стороны.
Чрезмерное использование autoUpdate может приводить к
потере производительности. Рекомендуется:
autoUpdate только для критических
элементов, требующих постоянной синхронизации с reference.После завершения жизненного цикла элемента необходимо:
autoUpdate для снятия всех
слушателей.const cleanup = autoUpdate(reference, floating, updatePosition);
// В нужный момент
cleanup();
floating.remove();
Правильная очистка предотвращает утечки памяти и ошибки в динамическом интерфейсе, особенно если плавающие элементы создаются и удаляются часто.
В React или Vue Floating UI можно интегрировать через хуки
(useFloating) или компоненты-обёртки. Хуки автоматически
управляют жизненным циклом:
autoUpdate при монтировании.computePosition при изменении props.const { x, y, reference, floating } = useFloating({
middleware: [offset(10), flip()],
});
return (
<>
<button ref={reference}>Open</button>
<div ref={floating} style={{ position: 'absolute', left: x ?? 0, top: y ?? 0 }}>
Tooltip
</div>
</>
);
Такой подход позволяет полностью абстрагировать управление жизненным циклом и обновлением позиции.
Жизненный цикл и обновления в Floating UI строятся вокруг принципов инициализации, динамического пересчета и очистки, где ключевую роль играют middleware и autoUpdate. Это позволяет создавать максимально гибкие и производительные плавающие элементы, адаптирующиеся к изменениям интерфейса.