Как перетаскивать и клонировать элементы в Svelte?

Я работаю над приложением визуального программирования, которое имеет два столбца.

Столбец слева представляет собой набор инструментов, из которого пользователи могут перетаскивать «элементы» в столбец справа, который представляет собой сценарий, который пользователь может собрать. Визуально это выглядит как этот пример.

Я пытаюсь реализовать это в Svelte. В каждой из двух моих колонок есть раздел each для заполнения его элементами.

У меня возникли трудности с перетаскиванием на работу с помощью svelte-dnd-action.

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

Еще одна менее серьезная вещь, которую я считаю неудобной, — это то, что все должно иметь идентификатор. Сейчас оба столбца загружаются из содержимого JSON при загрузке страницы. В итоге я написал функцию-обходчик, которая обходит проанализированные объекты и присваивает uuid всем элементам. Затем при перетаскивании я пытался клонировать и рекурсивно восстанавливать идентификаторы перетаскиваемого элемента.

Я пробовал различные «обратные вызовы» on:consider, on:finalize и т. д., но их настройка почти такая же, как если бы перетаскивание уже было выполнено (они добавляют элемент в конец списка).

Я получал различные ошибки, связанные с идентификаторами (элементы в each должны быть уникальными), вплоть до старой доброй ошибки «ничего не происходит», когда я могу инициировать действие перетаскивания, но перетаскиваемый элемент не принимается на другом конце. .

Как я могу заставить это работать? При необходимости я бы рассмотрел возможность перехода на другую библиотеку перетаскивания.

🤔 А знаете ли вы, что...
JavaScript используется для разработки современных одностраничных приложений (SPA), где весь контент загружается асинхронно.


70
1

Ответ:

Решено

В документации есть список примеров , один показывает, как элементы можно копировать при перетаскивании.

Код обработчика для копирования, но не в список источников:

import { dndzone, TRIGGERS, SHADOW_ITEM_MARKER_PROPERTY_NAME } from 'svelte-dnd-action';
// ...
let shouldIgnoreDndEvents = false;

function handleDndConsider(e) {
    const {trigger, id} = e.detail.info;
    if (trigger === TRIGGERS.DRAG_STARTED) {
        const idx = items.findIndex(item => item.id === id);
        const newId = `${id}_copy_${Math.round(Math.random() * 100000)}`;
        // the line below was added in order to be compatible with version svelte-dnd-action 0.7.4 and above 
        e.detail.items = e.detail.items.filter(item => !item[SHADOW_ITEM_MARKER_PROPERTY_NAME]);
        e.detail.items.splice(idx, 0, { ...items[idx], id: newId });
        items = e.detail.items;
        shouldIgnoreDndEvents = true;
    }
    else if (!shouldIgnoreDndEvents) {
        items = e.detail.items;
    }
    else {
        items = [...items];
    }
}
function handleDndFinalize(e) {
    if (!shouldIgnoreDndEvents) {
        items = e.detail.items;
    }
    else {
        items = [...items];
        shouldIgnoreDndEvents = false;
    }
}

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