Wrapper классы в контексте библиотеки Shopify Draggable представляют собой обёртки вокруг базового API, позволяющие создавать более удобный, читаемый и расширяемый код для реализации drag-and-drop функционала. Такой подход особенно полезен при необходимости интеграции Draggable в сложные интерфейсы с повторяющимися компонентами и кастомной логикой.
Инкапсуляция позволяет скрыть детали реализации и предоставить унифицированный интерфейс для работы с перетаскиваемыми элементами. В wrapper классе создаются методы для инициализации, подписки на события и управления состоянием элементов.
class DraggableWrapper {
constructor(containerSelector, options = {}) {
this.container = document.querySelector(containerSelector);
this.options = options;
this.draggable = null;
}
init() {
if (!this.container) return;
this.draggable = new Draggable(this.container, {
draggable: this.options.draggable || '.draggable-item',
mirror: this.options.mirror || { constrainDimensions: true },
plugins: this.options.plugins || [],
});
this._bindEvents();
}
_bindEvents() {
if (!this.draggable) return;
this.draggable.on('drag:start', (evt) => this.onDragStart(evt));
this.draggable.on('drag:move', (evt) => this.onDragMove(evt));
this.draggable.on('drag:stop', (evt) => this.onDragStop(evt));
}
onDragStart(evt) {
console.log('Drag started', evt.source);
}
onDragMove(evt) {
console.log('Dragging', evt.sensorEvent.clientX, evt.sensorEvent.clientY);
}
onDragStop(evt) {
console.log('Drag stopped', evt.source);
}
}
Ключевое здесь — выделение приватных методов
(_bindEvents) и публичных методов (init,
onDragStart), что делает wrapper гибким и безопасным для
расширения.
Wrapper класс можно расширять, добавляя новые методы для динамического добавления и удаления draggable элементов или изменения конфигурации на лету:
addItem(selector) {
const newItem = document.querySelector(selector);
if (newItem && this.draggable) {
this.draggable.add(newItem);
}
}
removeItem(selector) {
const item = document.querySelector(selector);
if (item && this.draggable) {
this.draggable.remove(item);
}
}
updateOptions(newOptions) {
this.options = { ...this.options, ...newOptions };
this.draggable.destroy();
this.init();
}
Этот подход позволяет поддерживать адаптивные интерфейсы и управлять элементами без необходимости полностью пересоздавать экземпляр Draggable.
Одним из преимуществ wrapper является централизованная обработка событий. Вместо прямой подписки на события Draggable можно реализовать систему колбеков или событийного эмиттера внутри класса:
on(eventName, callback) {
if (!this.draggable) return;
this.draggable.on(eventName, callback);
}
off(eventName, callback) {
if (!this.draggable) return;
this.draggable.off(eventName, callback);
}
Это создаёт чистый API для взаимодействия с внешними компонентами, позволяя подключать обработчики событий динамически.
Wrapper класс упрощает подключение плагинов Draggable, таких как
Plugins.SwapAnimation или
Plugins.ResizeMirror. Плагин можно передавать через опции
при инициализации, а wrapper обеспечивает корректное применение и
настройку:
import { SwapAnimation } from '@shopify/draggable';
const wrapper = new DraggableWrapper('#list', {
draggable: '.item',
plugins: [SwapAnimation],
});
wrapper.init();
Благодаря wrapper, добавление или удаление плагинов становится прозрачным и не требует изменения основного кода приложения.
Для интерфейсов с множеством списков или областей перетаскивания можно создать универсальный wrapper, поддерживающий несколько контейнеров:
class MultiContainerDraggable extends DraggableWrapper {
constructor(containers, options = {}) {
super(null, options);
this.containers = containers.map(sel => document.querySelector(sel));
}
init() {
this.draggable = new Draggable(this.containers, {
draggable: this.options.draggable || '.draggable-item',
plugins: this.options.plugins || [],
});
this._bindEvents();
}
}
Это позволяет реализовать перемещение элементов между списками с минимальной дополнительной логикой.
init, destroy, addItem,
removeItem, on обеспечивают удобство
использования.Wrapper классы становятся не только удобным инструментом для управления Draggable, но и основой для построения сложных drag-and-drop интерфейсов с высокой повторяемостью и поддержкой кастомной логики.