Native HTML5 Drag and Drop API

Dragula — это JavaScript-библиотека, упрощающая реализацию функциональности перетаскивания элементов между контейнерами. Она строится поверх Native HTML5 Drag and Drop API, но снимает большую часть сложности, связанной с событиями, манипуляцией классов и вычислением координат.

Библиотека обеспечивает следующие ключевые возможности:

  • Перетаскивание элементов между контейнерами без необходимости писать обработчики dragstart, dragover, drop.
  • Автоматическое клонирование элементов или их перемещение.
  • Простая кастомизация поведения, включая запрет на перетаскивание отдельных элементов или контейнеров.
  • События жизненного цикла для работы с началом, завершением и отменой перетаскивания.

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

Для начала работы необходимо подключить библиотеку и определить контейнеры:

import dragula from 'dragula';

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

const drake = dragula(containers);

Пояснение:

  • containers — массив DOM-элементов, между которыми разрешено перемещать элементы.
  • drake — объект Dragula, через который управляются события и настройки.

Настройка поведения

Dragula предоставляет объект настроек при инициализации. Основные свойства:

  • moves — функция, определяющая, можно ли перетаскивать элемент. Возвращает true или false.

    moves: function (el, source, handle, sibling) {
        return handle.classList.contains('handle');
    }
  • accepts — функция, определяющая, можно ли сбросить элемент в конкретный контейнер.

    accepts: function (el, target, source, sibling) {
        return !target.classList.contains('locked');
    }
  • copy — указывает, будет ли элемент копироваться при перетаскивании (true) или перемещаться (false).

Работа с событиями

Dragula предоставляет богатый набор событий для управления жизненным циклом перетаскивания:

  • drag — срабатывает при начале перетаскивания.

    drake.on('drag', function(el) {
        el.style.opacity = '0.5';
    });
  • drop — срабатывает при успешном перемещении элемента в контейнер.

    drake.on('drop', function(el, target, source, sibling) {
        el.style.opacity = '';
    });
  • over и out — реагируют на вход и выход элемента в контейнер.

  • cancel — срабатывает при отмене перетаскивания, например, если элемент был отпущен вне контейнера.

Кастомизация внешнего вида

Dragula автоматически добавляет CSS-классы:

  • .gu-mirror — создается копия перетаскиваемого элемента, которая следует за курсором.
  • .gu-hide — скрывает оригинальный элемент при перемещении.
  • .gu-unselectable — предотвращает выделение текста во время перетаскивания.

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

Поддержка нескольких контейнеров

Dragula позволяет работать с множеством контейнеров одновременно. При инициализации достаточно передать массив:

const drake = dragula([container1, container2, container3]);

Можно контролировать, в какие контейнеры разрешено перемещать элементы, через функцию accepts.

Клонирование элементов

Для реализации функционала «перетащить и скопировать» используется опция copy:

const drake = dragula(containers, { copy: true });

Если требуется копировать элементы только из конкретного контейнера:

copy: function(el, source) {
    return source.id === 'left';
}

Запрет перетаскивания определённых элементов

Функция moves позволяет ограничивать перетаскивание:

moves: function(el, source, handle, sibling) {
    return !el.classList.contains('locked');
}

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

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

Dragula не изменяет DOM, кроме перемещения элементов, поэтому данные формы и атрибуты сохраняются. Для синхронизации с состоянием приложения можно использовать событие drop:

drake.on('drop', function(el, target, source, sibling) {
    const updatedList = Array.from(target.children).map(item => item.dataset.id);
    console.log('Новая последовательность элементов:', updatedList);
});

Работа с асинхронными операциями

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

drake.on('drop', async function(el, target, source, sibling) {
    try {
        await sendUpdateToServer(target.id, el.dataset.id);
    } catch {
        drake.cancel(true);
    }
});

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

Для больших списков рекомендуется:

  • Использовать moves для ограничения перетаскиваемых элементов.
  • Минимизировать количество событий DOM на drag и over.
  • Избегать тяжелых вычислений при перемещении, делая их после завершения события drop.

Совместимость с Native HTML5 API

Dragula использует нативный HTML5 Drag and Drop для определения позиции курсора и контейнера, но не полагается на встроенные DataTransfer-данные. Это позволяет избежать проблем с совместимостью между браузерами и обеспечивает более плавное перетаскивание.


Dragula сочетает простоту использования с гибкостью настройки, позволяя создавать сложные интерфейсы с перетаскиваемыми элементами, минимизируя прямую работу с низкоуровневыми событиями Native HTML5 Drag and Drop API.