Множественный выбор элементов

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


Настройка контейнеров

Для работы с множественным выбором элементов первым шагом является определение контейнеров. Контейнеры — это HTML-элементы, содержащие draggable-элементы.

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

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

const drake = dragula(containers, {
    moves: (el, source, handle, sibling) => el.classList.contains('draggable'),
    copy: false,
    revertOnSpill: true
});

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

  • moves — функция, определяющая, можно ли перетаскивать элемент. Часто используется для фильтрации draggable-элементов.
  • copy — указывает, будет ли элемент копироваться при перемещении. Для множественного выбора чаще используют false.
  • revertOnSpill — возвращает элементы на исходное место, если они были сброшены вне контейнера.

Реализация множественного выбора

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

let selectedElements = [];

document.querySelectorAll('.draggable').forEach(el => {
    el.addEventListener('click', (e) => {
        if (e.ctrlKey || e.metaKey) {
            el.classList.toggle('selected');
            updateSelection(el);
        }
    });
});

function updateSelection(el) {
    if (el.classList.contains('selected')) {
        selectedElements.push(el);
    } else {
        selectedElements = selectedElements.filter(item => item !== el);
    }
}

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

  • ctrlKey или metaKey используется для множественного выбора без снятия предыдущего выбора.
  • Класс selected позволяет визуально выделять выбранные элементы.
  • Функция updateSelection управляет массивом выбранных элементов.

Перетаскивание группы элементов

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

drake.on('drag', (el) => {
    if (!el.classList.contains('selected')) return;
    
    selectedElements.forEach(sel => {
        if (sel !== el) {
            sel.style.display = 'none'; // временно скрыть остальные элементы
        }
    });
});

drake.on('drop', (el, target, source, sibling) => {
    selectedElements.forEach(sel => {
        sel.style.display = 'block'; // вернуть элементы после перемещения
        if (sel !== el) target.appendChild(sel);
    });
    selectedElements = [];
});

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

  • Событие drag используется для модификации поведения выбранных элементов во время перемещения.
  • Временное скрытие элементов предотвращает конфликт с DOM и визуальные артефакты.
  • В drop осуществляется фактическое перемещение всех выбранных элементов в новый контейнер.

Ограничение перемещений

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

const drake = dragula(containers, {
    accepts: (el, target, source, sibling) => {
        if (!el.classList.contains('selected')) return false;
        return target.dataset.type === el.dataset.type;
    }
});

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

  • accepts определяет, можно ли сбросить элемент в конкретный контейнер.
  • Использование data-атрибутов упрощает фильтрацию по типам элементов.

Стилизация и визуальная обратная связь

Выделение выбранных элементов и визуальные подсказки при перемещении повышают удобство использования. Обычно применяют CSS-классы:

.draggable {
    cursor: grab;
    transition: transform 0.2s;
}

.selected {
    border: 2px solid #007BFF;
    background-color: #E0F0FF;
}

.gu-mirror {
    opacity: 0.7;
    border: 1px dashed #007BFF;
}

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

  • .gu-mirror — временный элемент, который Dragula создает для визуализации перетаскивания.
  • Стили selected помогают пользователю видеть выбранные элементы при множественном выделении.
  • Плавные переходы делают интерфейс более отзывчивым.

Обработка событий Dragula

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

  • drag — элемент начал перетаскиваться.
  • drop — элемент сброшен в новый контейнер.
  • over / out — курсор находится над контейнером или покидает его.
  • cancel — перетаскивание отменено.
  • remove — элемент удален из контейнера.

Использование этих событий позволяет интегрировать множественное перемещение с сохранением состояния, логикой undo/redo или анимациями.