Клонирование элементов при перетаскивании

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

Основные принципы клонирования

В Dragula клонирование реализуется через параметр copy. Он может принимать два типа значений:

  1. Булево значение

    copy: true

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

  2. Функция

    copy: function (el, source) {
        return el.classList.contains('cloneable');
    }

    Функция получает два аргумента:

    • el — элемент, который перетаскивается;
    • source — контейнер, из которого производится перетаскивание.

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

Создание Dragula с клонированием

Простейший пример инициализации Dragula с клонированием всех элементов:

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

const drake = dragula(containers, {
    copy: true,
    revertOnSpill: true,
});

Здесь:

  • containers — массив контейнеров, между которыми разрешено перетаскивание;
  • copy: true — клонирование всех элементов;
  • revertOnSpill: true — если элемент отпущен вне контейнера, копия возвращается на исходное место.

Клонирование по условию

Если требуется клонировать только определённые элементы, можно использовать функцию:

const drake = dragula(containers, {
    copy: function(el, source) {
        return el.hasAttribute('data-clone');
    },
    accepts: function(el, target, source, sibling) {
        return true;
    },
    removeOnSpill: false
});

В этом примере элементы с атрибутом data-clone будут клонироваться, остальные — перемещаться. Параметр accepts позволяет дополнительно контролировать, в какие контейнеры можно помещать клонированный элемент.

Работа с событиями при клонировании

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

  • drag — вызывается при начале перетаскивания. Можно сохранять ссылку на исходный элемент:

    drake.on('drag', function(el) {
        console.log('Начало перетаскивания:', el);
    });
  • cloned — вызывается только при использовании copy: true:

    drake.on('cloned', function(clone, original, type) {
        console.log('Создан клон:', clone);
        clone.style.backgroundColor = 'lightyellow';
    });

    Здесь:

    • clone — новый элемент, который будет перемещаться;
    • original — исходный элемент;
    • type — строка 'mirror' (иногда используется для отражения).
  • drop — вызывается после завершения перетаскивания:

    drake.on('drop', function(el, target, source, sibling) {
        console.log('Элемент размещён в контейнере:', target);
    });

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

Отдельные аспекты клонирования

  • Стилизация зеркала (mirror) При перетаскивании Dragula создаёт временный элемент зеркало (mirror), который визуально следует за курсором. Его можно стилизовать через CSS:

    .gu-mirror {
        opacity: 0.8;
        border: 2px dashed #ccc;
        background-color: #f0f0f0;
    }
  • Управление удалением при сбросе Параметры removeOnSpill и revertOnSpill позволяют:

    • removeOnSpill: true — удалять клон, если он отпущен вне контейнера;
    • revertOnSpill: true — возвращать клон на исходное место.
  • Клонирование сложных элементов Если элемент содержит вложенные узлы и обработчики событий, рекомендуется использовать функцию cloneNode(true) для глубокого клонирования:

    copy: function(el) {
        return el.cloneNode(true);
    }

    Это предотвращает потерю структуры и вложенных событий.

Практические сценарии

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

  2. Списки с шаблонами элементов Шаблонные элементы остаются в исходном списке, а пользователи создают копии для заполнения данных.

  3. Динамическое клонирование с условиями Например, клонировать только элементы, удовлетворяющие определённым критериям (класс, атрибут, состояние).

Итоговые рекомендации

  • Для массового клонирования достаточно copy: true.
  • Для селективного клонирования использовать функцию с логикой проверки.
  • События drag, cloned и drop позволяют гибко управлять процессом.
  • Настройки removeOnSpill и revertOnSpill помогают контролировать поведение при ошибочном сбросе.
  • Для сложных элементов использовать глубокое клонирование cloneNode(true).

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