Инициализация Sortable

Для работы с Shopify Draggable необходимо подключить саму библиотеку. Обычно это делается через пакет @shopify/draggable в проекте на npm или через CDN:

import { Sortable } from '@shopify/draggable';

// или через CDN
// <script src="https://cdn.jsdelivr.net/npm/@shopify/draggable@1.0.0-beta.8/lib/draggable.bundle.js"></script>

После подключения создаётся новый экземпляр Sortable, который отвечает за перетаскивание элементов внутри контейнера. Базовый синтаксис:

const sortable = new Sortable(document.querySelectorAll('.container'), {
  draggable: '.item',
});

Здесь:

  • document.querySelectorAll('.container') — выбирает контейнеры, внутри которых будет работать сортировка.
  • draggable: '.item' — задаёт элементы, которые можно перетаскивать.

Основные опции Sortable

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

  • draggable – селектор элементов для перетаскивания.

  • handle – селектор внутри элемента, за который пользователь может «схватить» объект.

  • delay – задержка перед активацией перетаскивания (в миллисекундах).

  • mirror – объект с настройками зеркального элемента (копии перетаскиваемого объекта).

    • constrainDimensions: true – зеркальный элемент сохраняет размеры оригинала.
  • classes – объект для переопределения классов CSS:

    • sortable: 'my-sortable-class'
    • draggable: 'my-draggable-class'
    • dragging: 'my-dragging-class'

Пример расширенной инициализации с пользовательским handle и зеркалом:

const sortable = new Sortable(document.querySelectorAll('.container'), {
  draggable: '.item',
  handle: '.handle',
  delay: 150,
  mirror: {
    constrainDimensions: true,
  },
  classes: {
    dragging: 'dragging',
    sortable: 'sortable-container',
    draggable: 'draggable-item',
  },
});

События Sortable

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

  • sortable:start – срабатывает при начале перетаскивания.
  • sortable:sort – вызывается каждый раз, когда элемент перемещается в новом порядке.
  • sortable:stop – срабатывает при завершении перетаскивания.
  • sortable:sorted – окончательная перестановка элемента.
  • sortable:mirror:created – создание зеркального элемента.
  • sortable:mirror:destroyed – удаление зеркального элемента.

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

sortable.on('sortable:start', (event) => {
  console.log('Начало перетаскивания:', event.data.dragEvent.source);
});

sortable.on('sortable:sorted', (event) => {
  console.log('Элемент перемещён:', event.data.newIndex);
});

Настройка зеркального элемента (Mirror)

При перетаскивании Sortable создаёт визуальную копию элемента — mirror, которая следует за курсором. Управление зеркалом позволяет задавать ограничения и анимацию:

const sortable = new Sortable(document.querySelectorAll('.container'), {
  draggable: '.item',
  mirror: {
    constrainDimensions: true,
    appendTo: document.body, // зеркальный элемент добавляется в body
    xAxis: true,
    yAxis: true,
  },
});
  • appendTo – определяет, куда будет помещён зеркальный элемент.
  • xAxis и yAxis – ограничивают движение по конкретным осям.
  • constrainDimensions – сохраняет ширину и высоту оригинального элемента.

Множественные контейнеры и совместная сортировка

Sortable поддерживает работу с несколькими контейнерами одновременно. Это позволяет реализовать функциональность перетаскивания элементов между списками:

const containers = document.querySelectorAll('.container');
const sortable = new Sortable(containers, {
  draggable: '.item',
  mirror: { constrainDimensions: true },
});

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

sortable.on('sortable:sorted', (event) => {
  const { oldIndex, newIndex, source, over } = event.data;
  console.log(`Элемент перемещён из контейнера`, source, `в контейнер`, over);
});

Динамическое обновление элементов

Если список элементов меняется динамически (например, элементы добавляются через JavaScript), необходимо уведомить Sortable о новых элементах:

sortable.destroy(); // удаляет текущий экземпляр
sortable = new Sortable(document.querySelectorAll('.container'), {
  draggable: '.item',
});

Или использовать sortable.addDraggables для добавления новых элементов без полной инициализации:

const newItems = document.querySelectorAll('.container .new-item');
sortable.addDraggables(newItems);

Настройка анимации и визуальных эффектов

Для более плавного и наглядного перетаскивания можно использовать CSS-анимации и классы, добавляемые Sortable:

.draggable-item {
  transition: transform 0.2s ease;
}

.dragging {
  opacity: 0.8;
  box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}

Sortable автоматически добавляет класс dragging к элементу, за которым следует курсор, и обновляет его положение с помощью transform, что позволяет легко применять визуальные эффекты.

Управление ограничениями перемещения

Sortable поддерживает ограничение перемещения элементов через события и пользовательскую логику:

sortable.on('sortable:sort', (event) => {
  const { dragEvent } = event.data;
  if (dragEvent.source.dataset.fixed) {
    dragEvent.cancel(); // отменяет перемещение для фиксированного элемента
  }
});

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


Эта структура и возможности Sortable позволяют строить сложные интерактивные списки с полной кастомизацией поведения, визуальной индикацией, динамическим обновлением и поддержкой нескольких контейнеров, создавая гибкие интерфейсы drag-and-drop на JavaScript.