Работа с несколькими контейнерами одновременно

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

Инициализация Dragula для нескольких контейнеров

Создание Dragula-инстанса с несколькими контейнерами выполняется через передачу массива DOM-элементов:

const containers = [
    document.getElementById('container1'),
    document.getElementById('container2'),
    document.getElementById('container3')
];

const drake = dragula(containers);

Ключевые моменты:

  • Все элементы массива будут источниками и целями для перетаскивания.
  • Порядок контейнеров в массиве влияет только на внутреннюю организацию Dragula, не на логику перетаскивания.
  • Каждый контейнер может содержать любое количество элементов.

Ограничение перемещения между контейнерами

Dragula предоставляет возможность контролировать, куда можно перемещать элементы. Для этого используется опция moves и accepts:

const drake = dragula(containers, {
    moves: (el, source, handle, sibling) => {
        return !el.classList.contains('no-drag');
    },
    accepts: (el, target, source, sibling) => {
        return target.id !== 'container3';
    }
});
  • moves — определяет, какие элементы можно брать за перетаскивание. В примере элементы с классом no-drag нельзя перетаскивать.
  • accepts — определяет, можно ли вставить элемент в конкретный контейнер. Здесь элементы не могут попадать в container3.

События Dragula

При работе с несколькими контейнерами особенно важны события, которые позволяют отслеживать перемещения и обновлять данные:

  • drag — начинается процесс перетаскивания.
  • drop — элемент помещён в контейнер.
  • over — курсор находится над контейнером.
  • out — курсор покидает контейнер.
  • remove — элемент удалён, если включена опция removeOnSpill.

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

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

Особенности работы с событиями:

  • При работе с несколькими контейнерами важно различать source и target, чтобы корректно обновлять внутреннюю модель данных.
  • sibling позволяет определить, перед каким элементом был вставлен перетаскиваемый элемент.

Динамическое добавление контейнеров

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

const newContainer = document.getElementById('container4');
drake.containers.push(newContainer);
  • После добавления новый контейнер автоматически становится частью системы перетаскивания.
  • Можно комбинировать статические и динамические контейнеры без пересоздания Dragula-инстанса.

Ограничение на конкретные элементы

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

const drake = dragula(containers, {
    accepts: (el, target, source, sibling) => {
        if (source.id === 'container1' && target.id === 'container2') {
            return el.dataset.allowed === 'true';
        }
        return true;
    }
});
  • Такой подход полезен для реализации сложной логики: разрешать перенос только определённых типов элементов между конкретными контейнерами.

Визуальные эффекты при перемещении

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

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

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

.gu-mirror {
    background-color: rgba(0, 150, 255, 0.3);
    border: 2px dashed #0096ff;
}

Работа с контейнерами разной вложенности

Dragula корректно обрабатывает вложенные контейнеры:

  • Вложенные списки можно использовать как отдельные контейнеры, передавая их в массив containers.
  • Перетаскивание внутри вложенного контейнера и между уровнями должно учитывать accepts для предотвращения неправильного поведения.

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

При большом количестве элементов и контейнеров рекомендуется:

  1. Использовать делегирование событий для управления состоянием элементов.
  2. Ограничивать количество одновременно активных контейнеров, если интерфейс содержит сотни элементов.
  3. Минимизировать операции DOM в обработчиках событий drop и drag.

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