Dragula — это легковесная библиотека для реализации перетаскивания элементов (drag-and-drop) в веб-приложениях. Одной из мощных возможностей является автоматическое определение контейнеров, что позволяет динамически управлять списками и зонами перетаскивания без необходимости явного указания всех элементов.
Автоматическое определение контейнеров реализуется с помощью функции
containers, передаваемой в объект настроек Dragula. Эта
функция позволяет возвращать набор элементов, которые будут считаться
контейнерами для перетаскиваемых объектов. Основная идея — дать
библиотеке возможность работать с элементами, создаваемыми динамически,
или изменяющимися в DOM.
dragula({
containers: function () {
return document.querySelectorAll('.drag-container');
}
});
В этом примере Dragula автоматически определяет все элементы с
классом .drag-container как контейнеры. При добавлении
новых контейнеров в DOM достаточно, чтобы они соответствовали селектору,
и они сразу становятся зонами перетаскивания.
Dragula позволяет динамически изменять набор контейнеров даже после инициализации. Для этого можно использовать функции и методы, возвращающие актуальный список контейнеров:
function getContainers() {
return Array.from(document.getElementsByClassName('drag-container'));
}
const drake = dragula({ containers: getContainers() });
// Добавление нового контейнера
const newContainer = document.createElement('div');
newContainer.classList.add('drag-container');
document.body.appendChild(newContainer);
// Обновление контейнеров
drake.containers = getContainers();
Такой подход полезен, когда контейнеры создаются или удаляются динамически в ходе работы приложения.
Автоматически определяемые контейнеры полностью поддерживают систему
событий Dragula. Это позволяет отслеживать момент начала перетаскивания
(drag), завершения (drop) или отмены действия
(cancel):
drake.on('drag', function(el, source) {
console.log('Начато перетаскивание элемента', el, 'из контейнера', source);
});
drake.on('drop', function(el, target, source, sibling) {
console.log('Элемент', el, 'был перемещён в контейнер', target);
});
События работают независимо от того, был контейнер добавлен статически или динамически.
Иногда необходимо ограничить элементы, которые Dragula считает
контейнерами. Для этого функция containers может включать
проверку условий:
function filterContainers() {
return Array.from(document.querySelectorAll('.drag-container'))
.filter(container => container.dataset.active === 'true');
}
const drake = dragula({ containers: filterContainers });
Такой фильтр позволяет игнорировать элементы, которые внешне выглядят как контейнеры, но не предназначены для перетаскивания в текущем состоянии приложения.
Dragula не отслеживает изменения DOM по умолчанию, поэтому для автоматического добавления новых контейнеров можно использовать MutationObserver:
const observer = new MutationObserver(() => {
drake.containers = Array.from(document.querySelectorAll('.drag-container'));
});
observer.observe(document.body, { childList: true, subtree: true });
MutationObserver обеспечивает постоянное обновление списка контейнеров без ручного вмешательства, что делает Dragula удобным для сложных интерфейсов с динамическими списками.
Dragula поддерживает выбор элементов с учётом вложенности. Например, контейнерами могут быть не только прямые элементы, но и вложенные блоки внутри основного контейнера:
dragula({
containers: function() {
const parentContainers = document.querySelectorAll('.parent-container');
return Array.from(parentContainers).flatMap(parent => parent.querySelectorAll('.child-container'));
}
});
Этот подход полезен для интерфейсов с иерархическими списками, где перемещаемые элементы могут находиться на разных уровнях.
Функция containers работает совместно с другими опциями
Dragula, такими как moves, accepts и
invalid, что позволяет гибко настраивать перетаскивание.
Например, можно разрешить перемещение элементов только между
автоматически определяемыми контейнерами и запретить перемещение в
определённые зоны:
dragula({
containers: () => document.querySelectorAll('.drag-container'),
accepts: (el, target) => !target.classList.contains('no-drop')
});
В этом случае контейнеры определяются автоматически, но перемещать элементы можно не во все зоны, а только в разрешённые.
Автоматическое определение контейнеров делает Dragula особенно удобной для интерфейсов с динамическим контентом, обеспечивая гибкость и надежность при работе с любыми изменениями DOM.