Эмуляция событий перетаскивания

Dragula — это лёгкая JavaScript-библиотека для организации перетаскивания элементов между контейнерами и внутри одного контейнера. Её основной принцип построен на простоте: минимальная конфигурация и возможность быстрого внедрения функционала drag-and-drop без обширного кода.

Для начала работы создаются контейнеры, которые будут участвовать в перетаскивании:

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

dragula(containers) принимает массив DOM-элементов, которые будут взаимодействовать между собой. По умолчанию библиотека разрешает перемещение всех элементов между этими контейнерами.

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

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

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

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

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

События Dragula

Dragula генерирует несколько ключевых событий, которые позволяют полностью контролировать процесс перетаскивания:

  • drag — элемент начал перетаскиваться.
  • drop — элемент был помещён в контейнер.
  • over — элемент перемещён над контейнером.
  • out — элемент покинул контейнер.
  • cancel — перетаскивание было отменено.
  • cloned — событие срабатывает, если элемент был скопирован.

Пример подписки на события:

drake.on('drag', el => {
    el.style.opacity = '0.5';
});

drake.on('drop', (el, target, source, sibling) => {
    el.style.opacity = '1';
    console.log(`Элемент перемещён из ${source.id} в ${target.id}`);
});

drake.on('over', (el, container) => {
    container.style.background = '#f0f0f0';
});

drake.on('out', (el, container) => {
    container.style.background = '';
});

Эмуляция событий перетаскивания

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

Программное перемещение элементов

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

function simulateDragAndDrop(el, target) {
    const eventDragStart = new Event('dragstart', { bubbles: true, cancelable: true });
    el.dispatchEvent(eventDragStart);

    const eventDragEnter = new Event('dragenter', { bubbles: true });
    target.dispatchEvent(eventDragEnter);

    const eventDragOver = new Event('dragover', { bubbles: true });
    target.dispatchEvent(eventDragOver);

    const eventDrop = new Event('drop', { bubbles: true, cancelable: true });
    target.dispatchEvent(eventDrop);

    const eventDragEnd = new Event('dragend', { bubbles: true, cancelable: true });
    el.dispatchEvent(eventDragEnd);
}

В сочетании с Dragula можно использовать метод drake.start() для начала перетаскивания элемента:

drake.start(el); // Неофициальный способ, зависит от версии библиотеки
drake.end();     // Завершение перетаскивания

Проверка условий и событий

Для корректной эмуляции важно учитывать логическую проверку функций moves и accepts, чтобы элемент не был заблокирован настройками Dragula:

if (drake.moves(el) && drake.accepts(el, target, el.parentNode)) {
    simulateDragAndDrop(el, target);
}

Визуальные эффекты и классы

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

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

Эти классы позволяют создавать сложные анимации и стили, контролируя внешний вид процесса drag-and-drop.

.gu-mirror {
    box-shadow: 0 5px 15px rgba(0,0,0,0.3);
    opacity: 0.8;
}
.gu-transit {
    opacity: 0.5;
}

Работа с динамическими контейнерами

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

const newContainer = document.createElement('div');
document.body.appendChild(newContainer);
drake.containers.push(newContainer);

После добавления нового контейнера элементы можно перемещать туда без переинициализации всей библиотеки.

Советы по оптимизации

  • Использовать moves и accepts для минимизации лишних проверок на каждом событии.
  • Для больших списков применять revertOnSpill только при необходимости, чтобы избежать лишних DOM-операций.
  • Контролировать клонирование элементов через copy и событие cloned, чтобы избежать утечек памяти при динамических контейнерах.
  • При тестировании эмуляции всегда запускать события последовательно, иначе Dragula может некорректно обработать перемещение.

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