Отправка на сервер

Для работы с библиотекой Shopify Draggable необходимо установить пакет через npm или подключить через CDN. При установке через npm используется команда:

npm install @shopify/draggable

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

import { Sortable, Swappable, Droppable } from '@shopify/draggable';

Для CDN:

<script src="https://cdn.jsdelivr.net/npm/@shopify/draggable@1.0.0-beta.8/lib/draggable.bundle.js"></script>

После подключения библиотека готова к созданию перетаскиваемых элементов и обработке событий.


Инициализация Sortable для списка

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

const sortable = new Sortable(document.querySelectorAll('.draggable-list'), {
  draggable: '.draggable-item',
  mirror: {
    constrainDimensions: true
  }
});
  • draggable — CSS-селектор для элементов, которые можно перетаскивать.
  • mirror.constrainDimensions — сохраняет размеры оригинального элемента при создании зеркала.

Основные события Draggable

Draggable предоставляет мощный механизм событий для отслеживания действий пользователя. Основные события для отправки данных на сервер:

  • drag:start — начало перетаскивания элемента.
  • drag:move — движение элемента во время перетаскивания.
  • drag:stop — окончание перетаскивания.
  • sortable:stop — завершение сортировки, подходит для отправки нового порядка на сервер.

Пример подписки на событие окончания сортировки:

sortable.on('sortable:stop', (event) => {
  const items = [...event.data.container.children];
  const order = items.map((item, index) => ({
    id: item.dataset.id,
    position: index + 1
  }));
  sendOrderToServer(order);
});

Формирование данных для сервера

После перетаскивания важно собрать актуальный порядок элементов. Чаще всего используется массив объектов с идентификатором и позицией:

function getOrder(container) {
  return Array.from(container.children).map((item, index) => ({
    id: item.dataset.id,
    position: index + 1
  }));
}

Эта структура удобна для передачи в JSON и обработки на серверной стороне.


Отправка данных через Fetch API

Для отправки на сервер используется современный Fetch API. В примере отправка нового порядка элементов:

function sendOrderToServer(order) {
  fetch('/update-order', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ order })
  })
  .then(response => response.json())
  .then(data => console.log('Порядок сохранен', data))
  .catch(error => console.error('Ошибка при сохранении', error));
}

Особенности:

  • POST — метод передачи данных.
  • JSON.stringify — преобразование объекта в JSON для передачи.
  • Обработка ответа сервера — важно проверять успешность операции и ошибки.

Интеграция с сервером на примере Node.js

На серверной стороне можно использовать Express для обработки запроса:

const express = require('express');
const bodyParser = require('body-parser');

const app = express();
app.use(bodyParser.json());

app.post('/update-order', (req, res) => {
  const order = req.body.order;
  // Логика обновления в базе данных
  console.log('Получен новый порядок:', order);
  res.json({ success: true });
});

app.listen(3000, () => console.log('Сервер запущен на порту 3000'));

Обработка ошибок и валидация

Перед отправкой на сервер рекомендуется проверять данные:

function validateOrder(order) {
  return order.every(item => item.id && Number.isInteger(item.position));
}

Пример отправки только валидного порядка:

if (validateOrder(order)) {
  sendOrderToServer(order);
} else {
  console.error('Некорректные данные для отправки');
}

Использование Debounce для уменьшения количества запросов

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

function debounce(func, wait) {
  let timeout;
  return function(...args) {
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(this, args), wait);
  };
}

const sendOrderDebounced = debounce(sendOrderToServer, 300);

sortable.on('sortable:stop', (event) => {
  const order = getOrder(event.data.container);
  sendOrderDebounced(order);
});

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


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

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

function getAllOrders(containers) {
  return containers.map(container => ({
    containerId: container.dataset.id,
    items: getOrder(container)
  }));
}

sortable.on('sortable:stop', () => {
  const orders = getAllOrders(document.querySelectorAll('.draggable-list'));
  sendOrderToServer(orders);
});

Такая организация упрощает работу с множеством списков и позволяет серверу получать полную информацию о состоянии интерфейса.


Настройка заголовков для авторизации

Для защищенных API можно передавать токен:

fetch('/update-order', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer ' + token
  },
  body: JSON.stringify({ order })
});

Это обеспечит корректную проверку прав пользователя на изменение порядка элементов.


Обновление интерфейса после успешной отправки

После успешного запроса можно визуально подтвердить пользователю, что изменения сохранены:

.then(data => {
  if (data.success) {
    document.querySelector('#status').textContent = 'Порядок сохранен';
  }
});

Сочетание Shopify Draggable, правильной обработки событий и надежной отправки данных обеспечивает гибкое и интерактивное управление списками на фронтенде с сохранением состояния на сервере.