Адаптеры и обертки

Dragula — это легковесная библиотека для реализации перетаскивания элементов между контейнерами в веб-приложениях. Основная цель библиотеки — предоставление простого и интуитивно понятного API для работы с drag-and-drop, без необходимости глубокого погружения в низкоуровневые события мыши или touch-события.

В Dragula ключевыми элементами являются контейнеры, содержащие элементы для перетаскивания, и элементы, которые перемещаются между этими контейнерами. Контейнеры передаются в библиотеку через массив или DOM-элементы, а элементы внутри них идентифицируются автоматически.

Инициализация Dragula

Создание экземпляра Dragula производится с помощью функции dragula(containers, options).

const containers = [document.getElementById('left'), document.getElementById('right')];

const drake = dragula(containers, {
    moves: (el, source, handle, sibling) => handle.classList.contains('handle'),
    copy: false,
    revertOnSpill: true
});

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

  • moves(el, source, handle, sibling) — функция, определяющая, можно ли перетаскивать конкретный элемент. Возвращает true или false.
  • copy — при значении true перемещаемый элемент копируется, при false — перемещается.
  • revertOnSpill — при значении true элемент возвращается на место, если был “выпущен” вне контейнеров.

События Dragula

Dragula предоставляет ряд событий для управления поведением элементов:

  • drag — срабатывает при начале перетаскивания.
  • drop — происходит после завершения перетаскивания в новый контейнер.
  • over и out — указывают на наведение элемента на контейнер или выход из него.
  • cancel — отменяет перетаскивание.

Пример использования событий:

drake.on('drag', function(el) {
    el.classList.add('is-dragging');
});

drake.on('drop', function(el, target, source, sibling) {
    el.classList.remove('is-dragging');
    console.log(`Элемент ${el.textContent} перемещен из ${source.id} в ${target.id}`);
});

Адаптеры и обертки

Адаптер в контексте Dragula — это слой абстракции, который позволяет интегрировать библиотеку с различными фреймворками и архитектурами, сохраняя единый API для работы с элементами DOM.

Обертка — это вспомогательный компонент, инкапсулирующий Dragula в более удобный интерфейс для конкретного проекта. Она может добавлять кастомную логику, управление событиями или дополнительные проверки.

Примеры адаптеров

  1. Адаптер для React

В React часто используют компонент-обертку для Dragula:

import React, { useEffect, useRef } from 'react';
import dragula from 'dragula';
import 'dragula/dist/dragula.css';

function DragulaContainer({ children }) {
    const containerRef = useRef(null);

    useEffect(() => {
        const drake = dragula([containerRef.current]);
        drake.on('drop', (el, target, source) => {
            console.log('Элемент перемещен', el);
        });

        return () => drake.destroy();
    }, []);

    return <div ref={containerRef}>{children}</div>;
}

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

  1. Адаптер для Vue

В Vue создают директиву для управления контейнерами:

import dragula from 'dragula';
import 'dragula/dist/dragula.css';

export default {
    mounted(el, binding) {
        const drake = dragula([el], binding.value || {});
        el.__drake__ = drake;
    },
    unmounted(el) {
        if (el.__drake__) {
            el.__drake__.destroy();
        }
    }
};

Директива позволяет подключать Dragula к любому элементу Vue-шаблона и автоматически очищать ресурсы при удалении компонента.

Кастомизация поведения через адаптеры

Адаптеры и обертки дают возможность:

  • Добавлять условия перетаскивания (moves, accepts).
  • Управлять визуальной обратной связью (например, подсветка контейнера).
  • Интегрировать Dragula с системами управления состоянием, такими как Redux или Vuex.
  • Расширять функционал Dragula дополнительными анимациями или эффектами.

Создание собственной обертки

Простейший шаблон обертки:

class DragulaWrapper {
    constructor(containers, options = {}) {
        this.drake = dragula(containers, options);
        this._initEvents();
    }

    _initEvents() {
        this.drake.on('drag', this.onDrag.bind(this));
        this.drake.on('drop', this.onDrop.bind(this));
    }

    onDrag(el) {
        el.classList.add('dragging');
    }

    onDrop(el, target, source) {
        el.classList.remove('dragging');
        console.log(`Перемещен элемент ${el.id}`);
    }

    destroy() {
        this.drake.destroy();
    }
}

Такой подход позволяет централизованно управлять логикой перетаскивания и легко интегрировать Dragula в сложные приложения.

Интеграция с другими библиотеками

Адаптеры упрощают совместную работу Dragula с:

  • Системами виртуального DOM (React, Vue, Svelte).
  • CSS-фреймворками (Tailwind, Bootstrap) для динамического применения стилей.
  • Сложными интерфейсами с несколькими контейнерами и вложенными элементами.

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