В SvelteKit drag and drop реализуется с использованием как встроенных
возможностей HTML5, так и специализированных UI-библиотек, которые
упрощают работу с событиями dragstart,
dragover, drop и другими. Основная задача
таких библиотек — минимизировать прямое управление DOM и предоставить
декларативный подход через компоненты и actions.
В SvelteKit ключевую роль играют actions — функции,
которые можно привязать к DOM-элементу через атрибут use:.
Для drag and drop actions обычно обрабатывают:
dragstart — начало перетаскивания элемента, здесь
задаётся dataTransfer и дополнительные параметры (например,
идентификатор объекта).dragover — событие, вызываемое при наведении на целевой
контейнер, важно предотвращать стандартное поведение через
event.preventDefault().drop — окончание перетаскивания, здесь извлекаются
данные из dataTransfer и обновляется состояние
приложения.Пример базового action для draggable элемента:
export function draggable(node, { id }) {
node.draggable = true;
const handleDragStart = (event) => {
event.dataTransfer.setData('text/plain', id);
event.dataTransfer.effectAllowed = 'move';
};
node.addEventListener('dragstart', handleDragStart);
return {
destroy() {
node.removeEventListener('dragstart', handleDragStart);
}
};
}
Существуют несколько библиотек, которые предоставляют готовые решения для drag and drop в SvelteKit:
svelte-dnd-action
Пример интеграции svelte-dnd-action:
<script>
import { dndzone } from 'svelte-dnd-action';
let items = [
{ id: 1, name: 'Элемент 1' },
{ id: 2, name: 'Элемент 2' },
{ id: 3, name: 'Элемент 3' }
];
function handleDrop({ detail: { items: newItems } }) {
items = newItems;
}
</script>
<ul use:dndzone={{ items, flipDurationMs: 200 }} on:consider={handleDrop} on:finalize={handleDrop}>
{#each items as item}
<li>{item.name}</li>
{/each}
</ul>
flipDurationMs задаёт анимацию перемещения
элементов.consider вызывается при любом изменении позиции
элемента, а finalize — когда перетаскивание завершено.svelte-drag
Draggable и
Droppable для обёртки элементов.Пример использования:
<script>
import { Draggable, Droppable } from 'svelte-drag';
let items = ['A', 'B', 'C'];
</script>
<Droppable let:dropData on:drop={(e) => console.log(e.detail)}>
{#each items as item (item)}
<Draggable let:dragData>
<div>{item}</div>
</Draggable>
{/each}
</Droppable>
dragData содержит информацию о перетаскиваемом
объекте.dropData передаёт состояние целевой зоны для обработки
логики вставки.Важно помнить, что drag and drop в SvelteKit тесно связан с реактивностью состояния. Изменение порядка элементов или перемещение между списками должно напрямую отражаться в реактивных переменных. Это позволяет избегать прямых манипуляций DOM и использовать декларативный подход.
Например, при переносе элемента из одного списка в другой:
<script>
let listA = ['1', '2', '3'];
let listB = ['4', '5'];
function moveItem(item, from, to) {
from = from.filter(i => i !== item);
to = [...to, item];
}
</script>
События drop можно использовать для вызова
moveItem с соответствующими списками.
UI-библиотеки для SvelteKit часто включают поддержку FLIP-анимаций, плавного перемещения элементов и подсветки drop-зоны. Это важно для UX, особенно при работе со списками и сетками.
flipDurationMs в svelte-dnd-action задаёт
скорость анимации перемещения.accept или
group, чтобы элемент попадал только в определённые
контейнеры.dragenter, dragleave, что позволяет
реализовать сложные сценарии, например, проверку валидности
перемещения.dragover, иначе drop
может не срабатывать.SvelteKit и специализированные drag and drop библиотеки создают мощный инструмент для разработки динамичных интерфейсов с минимальной ручной работой с DOM, полностью используя реактивность фреймворка.