Ограничения на перетаскиваемые элементы

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


Фильтрация элементов с помощью invalid

Метод invalid позволяет определить, какие элементы не подлежат перетаскиванию. Этот метод принимает функцию, которая получает текущий элемент и возвращает true, если элемент нельзя перетаскивать, и false, если перетаскивание разрешено.

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

const drake = dragula([container1, container2], {
  invalid: function(el, handle) {
    // Запрет на перетаскивание элементов с классом 'no-drag'
    return el.classList.contains('no-drag');
  }
});
  • el — элемент, на котором инициируется перетаскивание.
  • handle — элемент, по которому производится клик для начала перетаскивания. Может совпадать с el или быть дочерним элементом.

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


Контроль разрешённых контейнеров с помощью accepts

Функция accepts задаёт правила, куда элемент можно помещать. Она вызывается каждый раз при попытке перемещения элемента в другой контейнер и должна возвращать true, если вставка разрешена, и false, если нет.

Пример ограничения по контейнерам:

const drake = dragula([container1, container2, container3], {
  accepts: function(el, target, source, sibling) {
    // Разрешаем перемещать элементы только в container2
    return target === container2;
  }
});
  • el — перетаскиваемый элемент.
  • target — контейнер, в который пытаются вставить элемент.
  • source — исходный контейнер.
  • sibling — элемент, перед которым произойдёт вставка (null, если в конец).

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


Ограничение перемещения по точке захвата с помощью moves

Функция moves позволяет определить, по каким элементам внутри перетаскиваемого блока разрешено инициировать перетаскивание. Это особенно полезно, когда у карточки есть несколько интерактивных элементов (кнопки, ссылки), которые не должны запускать drag-and-drop.

Пример ограничения точки захвата:

const drake = dragula([container1, container2], {
  moves: function(el, source, handle, sibling) {
    // Разрешаем перетаскивать только по элементу с классом 'handle'
    return handle.classList.contains('handle');
  }
});
  • handle — элемент, по которому пользователь нажимает и тянет.
  • Использование moves позволяет создавать удобный пользовательский интерфейс, где перетаскивание начинается только за специально выделенные области карточки.

Ограничение по порядку вставки

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

  • Запрет на перестановку определённых элементов.
  • Фиксацию первого или последнего элемента в списке.
  • Создание сортируемых списков с динамическими правилами.

Пример закрепления первого элемента:

const drake = dragula([container], {
  accepts: function(el, target, source, sibling) {
    // Первый элемент нельзя передвигать
    if (sibling && sibling === container.firstElementChild) return false;
    return true;
  }
});

Ограничение по типу элемента

Для удобного управления можно использовать кастомные атрибуты или классы для элементов и проверять их в функциях invalid и accepts.

Пример ограничения по типу:

const drake = dragula([container1, container2], {
  accepts: function(el, target) {
    // Разрешаем перемещать только элементы с data-type="draggable"
    return el.dataset.type === "draggable";
  }
});

Такой подход обеспечивает гибкость и масштабируемость, особенно если количество типов элементов в приложении большое.


Ограничение по количеству элементов в контейнере

Dragula позволяет ограничить количество элементов в целевом контейнере через проверку target.children.length в функции accepts.

Пример ограничения количества элементов:

const drake = dragula([container1, container2], {
  accepts: function(el, target) {
    // В контейнере не должно быть больше 5 элементов
    return target.children.length < 5;
  }
});

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


Ограничение движения за пределы контейнера

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

const drake = dragula([container], {
  accepts: function(el, target, source) {
    return source === target;
  }
});

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


Совмещение всех ограничений

Функции invalid, moves и accepts можно комбинировать для создания сложной логики перетаскивания. Dragula применяет их в следующем порядке:

  1. Проверка invalid — элемент полностью исключается из перетаскивания.
  2. Проверка moves — определяется, можно ли инициировать перетаскивание по данному handle.
  3. Проверка accepts — проверяется возможность вставки элемента в выбранный контейнер и перед выбранным sibling.

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