Определение допустимых контейнеров

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

Основные концепции контейнеров

В Dragula контейнер — это HTML-элемент, который может содержать перетаскиваемые элементы (драггеры). Библиотека работает с массивом контейнеров, передаваемым при инициализации:

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

const drake = dragula(containers);

Ключевой момент: контейнеры не могут быть динамически добавлены в процессе инициализации без последующего вызова метода drake.containers.push(newContainer) или полной переинициализации.

Ограничение контейнеров

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

const drake = dragula(containers, {
    accepts: function (el, target, source, sibling) {
        // el — перетаскиваемый элемент
        // target — контейнер, в который пытаются вставить
        // source — контейнер, из которого взят элемент
        // sibling — элемент перед которым вставляется, или null
        return target.id !== 'forbidden-container';
    }
});

Важно: функция accepts должна возвращать логическое значение. true разрешает вставку, false запрещает. Это основной механизм ограничения контейнеров, позволяющий реализовать сложную логику — например, разные типы элементов могут быть разрешены только в определённых списках.

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

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

const newContainer = document.getElementById('new-list');
drake.containers.push(newContainer);

При этом автоматически сохраняются текущие настройки, включая функцию accepts и события перетаскивания. Это особенно удобно для приложений с динамическими списками или табами.

Контроль перетаскивания между контейнерами

Можно ограничивать не только разрешённые контейнеры, но и перемещение между конкретными парами. Для этого используется более сложная логика внутри функции accepts:

const drake = dragula(containers, {
    accepts: function (el, target, source, sibling) {
        if (source.id === 'left-list' && target.id === 'right-list') {
            return true;
        }
        if (source.id === 'right-list' && target.id === 'left-list') {
            return false;
        }
        return false;
    }
});

Пояснение: в этом примере элементы могут перемещаться только из left-list в right-list. Любые другие попытки вставки будут блокированы.

Способы ограничения по типу элемента

Иногда требуется, чтобы контейнеры принимали только определённые элементы. Это реализуется через проверку классов или атрибутов внутри accepts:

accepts: function (el, target, source, sibling) {
    return el.classList.contains('draggable-item') && target.dataset.accepts === el.dataset.type;
}

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

  • Использование data-* атрибутов позволяет гибко управлять допустимыми комбинациями элементов и контейнеров.
  • Проверка классов предотвращает случайное перетаскивание неподходящих элементов.

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

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

const nestedContainers = document.querySelectorAll('.nested-list');
nestedContainers.forEach(container => drake.containers.push(container));

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

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

Кроме accepts, Dragula предоставляет события drag, drop, over, out, которые позволяют отслеживать и управлять процессом перетаскивания:

drake.on('over', function (el, container, source) {
    if (container.id === 'restricted-container') {
        container.classList.add('highlight-denied');
    }
});

drake.on('out', function (el, container, source) {
    container.classList.remove('highlight-denied');
});

Это позволяет визуально сигнализировать пользователю о допустимости вставки элемента в контейнер.

Рекомендации по структуре контейнеров

  • Использовать уникальные идентификаторы (id) для контейнеров для облегчения логики проверки.
  • Обозначать типы контейнеров через data-* атрибуты для масштабируемой системы перетаскивания.
  • Поддерживать отдельный массив контейнеров, чтобы можно было динамически добавлять или удалять их без переинициализации Dragula.

Контроль допустимых контейнеров — основа безопасного и предсказуемого поведения Dragula. Грамотно настроенная функция accepts совместно с правильно структурированными контейнерами позволяет строить сложные интерфейсы с множественными зонами перетаскивания и правилами перемещения элементов.