Svelte интеграция

Для работы с Popper.js в проекте на Svelte необходимо установить библиотеку через npm:

npm install @popperjs/core

После установки импортирование происходит стандартным образом:

import { createPopper } from '@popperjs/core';

Popper.js создаёт «попперы» — элементы, позиционирующиеся относительно других элементов (reference elements). В Svelte этот процесс удобно инкапсулировать в action.


Создание action для Popper.js

В Svelte actions позволяют добавлять функциональность к DOM-элементам. Action для Popper.js можно оформить так:

// popper.js
import { createPopper } from '@popperjs/core';

export function popper(node, options) {
    let popperInstance;

    function init(reference) {
        if (popperInstance) {
            popperInstance.destroy();
        }
        popperInstance = createPopper(reference, node, options);
    }

    return {
        upd ate(newOptions) {
            if (popperInstance) {
                popperInstance.setOptions(newOptions);
            }
        },
        destroy() {
            if (popperInstance) {
                popperInstance.destroy();
            }
        },
        init
    };
}

Пояснение ключевых моментов:

  • node — это DOM-элемент, к которому применяется action, обычно сам popper.
  • options — конфигурация Popper.js, включает placement, modifiers и прочее.
  • Метод init позволяет привязать popper к reference элементу динамически.
  • update обеспечивает возможность обновления параметров после инициализации.
  • destroy корректно удаляет Popper.js при размонтировании компонента.

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

<script>
    import { popper } from './popper.js';
    import { onMount } from 'svelte';

    let referenceButton;
    let tooltip;

    let popperAction;

    onMount(() => {
        popperAction.init(referenceButton);
    });
</script>

<button bind:this={referenceButton}>Наведи на меня</button>
<div
    bind:this={tooltip}
    use:popper={{ placement: 'top', modifiers: [{ name: 'offset', options: { offset: [0, 8] } }] }}
    style="background: #333; color: #fff; padding: 4px 8px; border-radius: 4px;"
>
    Подсказка
</div>

Особенности:

  • bind:this позволяет получить прямую ссылку на DOM-элемент.
  • Action подключается через use:popper.
  • При изменении placement или modifiers action автоматически обновит Popper.js.

Настройка модификаторов

Popper.js поддерживает гибкую систему modifiers, позволяющую изменять поведение и позиционирование:

use:popper={{
    placement: 'right',
    modifiers: [
        {
            name: 'offset',
            options: { offset: [10, 20] } // сдвиг по X и Y
        },
        {
            name: 'flip',
            options: { fallbackPlacements: ['top', 'bottom'] } // альтернативные позиции при переполнении
        },
        {
            name: 'preventOverflow',
            options: { padding: 8 } // защита от выхода за границы окна
        }
    ]
}}

Ключевые модификаторы:

  • offset — смещение относительно reference элемента.
  • flip — автоматический выбор подходящего положения при нехватке места.
  • preventOverflow — предотвращает выход поппера за видимую область.

Динамическое обновление позиции

В Svelte popper можно обновлять при изменении размеров или состояния компонента:

$: if (someCondition) {
    popperAction.update({
        placement: 'bottom',
        modifiers: [{ name: 'offset', options: { offset: [0, 12] } }]
    });
}
  • $: реактивная метка Svelte, позволяющая обновлять Popper.js при изменении переменной.
  • Метод update корректно применяет новые параметры без пересоздания поппера.

Управление жизненным циклом

Popper.js нужно корректно удалять при размонтировании компонента. Action Svelte автоматически вызывает destroy:

<div use:popper={{ placement: 'left' }}>
    Контент
</div>

При удалении DOM-узла Popper.js завершает работу, освобождая ресурсы.


Работа с анимацией и переходами

Svelte предоставляет встроенные transition и animation для элементов. Попперы совместимы с ними:

<div
    use:popper={{ placement: 'top' }}
    transition:fade={{ duration: 200 }}
>
    Подсказка
</div>
  • Анимация fade не мешает корректной позиции Popper.js.
  • Можно комбинировать с динамическим изменением placement для плавных эффектов.

Поддержка нескольких popper-элементов

Action позволяет создавать несколько popper-элементов с разными reference:

{#each items as item}
    <button bind:this={item.ref}>{item.label}</button>
    <div
        bind:this={item.popper}
        use:popper={{ placement: 'bottom' }}
    >
        {item.tooltip}
    </div>
{/each}
  • Каждый popper имеет свой экземпляр createPopper.
  • Рекомендовано хранить ссылки на popperAction для управления отдельными экземплярами.

Совместимость с reactive store

Svelte store можно использовать для управления видимостью и положением поппера:

<script>
    import { writable } from 'svelte/store';
    let showTooltip = writable(false);
</script>

<button on:mouseenter={() => showTooltip.se t(true)}
        on:mouseleave={() => showTooltip.set(false)}>
    Наведи на меня
</button>

{#if $showTooltip}
    <div use:popper={{ placement: 'top' }}>Подсказка</div>
{/if}
  • Store управляет видимостью, Popper.js автоматически обновляется при монтировании элемента.
  • Можно расширять логику для сложных UI, включая модальные окна и dropdown-меню.

Эти методы обеспечивают полную интеграцию Popper.js с Svelte, сохраняя реактивность, поддержку динамических изменений и правильное управление жизненным циклом компонентов.