Документация/API
makeSortableList
Делает контейнер сортируемым списком — черновик перестраивается во время драга и записывается обратно при броске.
Страница переведена ИИ и может содержать неточности. Читать английский оригинал
function makeSortableList<T>( target: MaybeElementRef, options: SortableListOptions<T>,): SortableListReturn<T>;Делает контейнер сортируемым списком. Рендерите возвращённый items (порядок черновика), а не свой массив: бросок записывается обратно в options.items после onDrop, если только event.preventDefault() не оставляет event.result вам.
const list = useTemplateRef<HTMLElement>('list');
const { items } = makeSortableList(list, { items: tasks, group: 'board' });
Строки списка вызывают makeSortableItem. См.
сортируемые списки и
списки с общими элементами.
Загружаем демо…
<script setup lang="ts">
import { ref } from 'vue';
import { DnDProvider } from '@vue-dnd-kit/core';
import Segmented from './Segmented.vue';
import Tiles from './Tiles.vue';
const strategy = ref<'vertical' | 'horizontal' | 'grid'>('grid');
const placeholder = ref<'item' | 'indicator'>('item');
const behavior = ref<'sort' | 'swap'>('sort');
</script>
<template>
<DnDProvider>
<div class="demo">
<div class="switches">
<Segmented v-model="strategy" name="strategy" :options="['vertical', 'horizontal', 'grid']" />
<Segmented v-model="placeholder" name="placeholder" :options="['item', 'indicator']" />
<Segmented v-model="behavior" name="behavior" :options="['sort', 'swap']" />
</div>
<code class="call">makeSortableList(el, { strategy: '{{ strategy }}', placeholder: '{{ placeholder }}', behavior: '{{ behavior }}' })</code>
<Tiles :strategy="strategy" :placeholder="placeholder" :behavior="behavior" />
</div>
</DnDProvider>
</template>
<style scoped>
.demo {
display: flex;
flex-direction: column;
align-items: center;
gap: 18px;
max-width: 100%;
}
.switches {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 16px;
}
.call {
max-width: 100%;
padding: 6px 10px;
overflow-x: auto;
border-radius: 8px;
background: color-mix(in srgb, currentColor 6%, transparent);
font: 11px/1.4 ui-monospace, Menlo, Consolas, monospace;
white-space: nowrap;
color: #42b883;
}
</style>Опции
Опции makeSortableList. Компонент может создавать несколько списков (и деревьев): каждый элемент, отрендеренный в нём, относится к самому внутреннему из них, чей DOM-элемент его содержит.
Опции принимают значение, ref или геттер (overlay, overOverlay, dropAnimation, overDropAnimation, animation — значение или ref) и читаются, когда они нужны списку, поэтому изменение вступает в силу не позже следующего драга. Исключения: id и group читаются один раз, при создании списка; items — это сама модель; функции (getKey, filter, clone, createItem, колбэки) передаются как есть.
SortableItems<T>Источник истины. Записываемый ref получает новый массив при броске, сразу после onDrop. Источник только для чтения (геттер, readonly ref, computed) так не может: вызовите event.preventDefault() и примените event.result сами. Если оставить такой бросок библиотеке, он ничего не изменит, и dev-сборки об этом предупредят.
(item: T) => KeyПо умолчанию — item.id или сам элемент для примитивов. Также задаёт ключ для makeSortableItem({ item }).
(item: T) => booleanПоказывает только элементы, для которых возвращает true (поиск, тег): они в items (возвращаемом), и драг сортирует среди них. Остальные сохраняют свои места в источнике: бросок записывает весь массив, и каждый скрытый элемент по-прежнему стоит после показанного, за которым шёл (после ближайшего оставшегося на месте, если тот двигался). Реактивна: то, что она читает (ref с запросом), применяется сразу. e.to.index и activeIndex считают показанные элементы.
KeyПо умолчанию — useId(), совпадает при рендере на сервере и на клиенте. Читается один раз.
stringзначение · ref · геттерНазвание списка для людей: тексты для скринридеров называют его вместо id (position 2 of 5 in Garden).
unknownзначение · ref · геттерЛюбые сведения о списке как о цели: события передают их как over.data, пока над ним драг.
ActivationOptionsзначение · ref · геттерКак нажатие на элементы этого списка начинает драг, вместо activation провайдера (собственная опция элемента важнее). Читается в начале нажатия.
Componentзначение · refКомпонент оверлея для элементов этого списка (собственный overlay элемента важнее). Получает OverlayProps и сохраняется на весь драг, в том числе над другими списками, если только у цели под драгом нет собственного оверлея (overOverlay). Ref, переключённый посреди драга, сразу его меняет.
Componentзначение · refЧто показывает оверлей, пока над этим списком драг, который список принимает, из какого бы списка он ни пришёл: компонент, который получает OverlayProps и собственный оверлей драга как слот по умолчанию (см. DroppableOptions.overOverlay). Читается на лету.
DropAnimationзначение · refКак приземляется оверлей, когда заканчивается драг элементов этого списка, вместо dropAnimation провайдера (собственная у элемента важнее; у цели — важнее обеих). Читается при броске.
DropAnimationзначение · refКак приземляется оверлей, когда его бросают в этот список, из какого бы списка он ни пришёл: важнее dropAnimation перетаскиваемого элемента и провайдера. Читается при броске.
Modifier[]значение · ref · геттерМодификаторы для драгов элементов этого списка; применяются после modifiers провайдера (собственные modifiers элемента важнее). Например, [restrictToVerticalAxis], чтобы элементы вертикального списка не сходили со своей оси. Читается в начале драга.
'x' | 'y'значение · ref · геттерФиксирует драги элементов этого списка по одной оси: 'y' для вертикального списка, 'x' для горизонтального (собственный axis элемента важнее). Фиксация идёт после модификаторов, поэтому держится, что бы они ни делали. Читается в начале драга.
string | SortableGroupOptions<T>Списки с одинаковым именем группы обмениваются элементами. По умолчанию — своя отдельная группа. Читается один раз.
AcceptModeзначение · ref · геттерМульти-драг элементов нескольких типов: принять (group.put) нужно все элементы ('all', по умолчанию) или некоторые ('some').
SortableStrategyзначение · ref · геттерПо умолчанию 'vertical'.
SortableBehaviorзначение · ref · геттер'swap': перетаскиваемый элемент на лету меняется местами с тем, на который наведён; если вернуться на него или уйти со списков, обмен откатывается. Списки одной группы, где оба используют обмен, обмениваются элементами между собой: элемент под драгом переезжает на место перетаскиваемого, поэтому он должен уметь покидать свой список (group.pull: true) и попадать в список перетаскиваемого (group.put). Мульти-драг вместо этого сортирует. По умолчанию 'sort'.
SortablePlaceholderзначение · ref · геттер'indicator': список не двигается, а indicator показывает, куда пойдёт бросок. По умолчанию 'item'.
MultipleModeзначение · ref · геттерРежим мульти-драга для драгов, которые начинаются в этом списке. По умолчанию 'group'. Читается в начале драга.
booleanзначение · ref · геттерfalse: элементы нельзя переставлять внутри этого списка (палитры).
(item: T) => TСоздаёт копии (pull: 'clone', клавиша-модификатор копирования). Обязательна для копирования.
(active: Active) => T | T[]Принимает обычные перетаскиваемые элементы извне: создаёт элемент для вставки. С клавиатуры стрелка в сторону списка забирает перетаскиваемый элемент в список (на его уровне, как при переносе между списками), и созданный элемент дальше движется по слотам, как любой другой.
Для драга извне страницы (external) её спрашивают дважды: пока драг удерживают — об элементе, который показывает, куда он попадёт (тогда известны только active.external.fileTypes и types), и при броске, с его данными (active.external.ready), — о том, что вставляется. Массив элементов вставляется весь туда, где был слот: по элементу на файл.
ExternalAcceptзначение · ref · геттерПринимает драги извне страницы: файлы, ссылки, текст (см. ExternalAccept). Список освобождает для них место, как для обычного перетаскиваемого элемента, с createItem — она ему нужна. Элементам его группы, перетащенным из другого окна приложения (native), не нужна ни одна из этих опций: они попадают в список как есть. Значение, ref или геттер, читается вживую.
DropOutsideзначение · ref · геттерБросок вне всех целей: оставить элементы там, где плейсхолдер, отменить или удалить их. По умолчанию 'placeholder' ('cancel' при placeholder: 'indicator'). Читается при броске.
LayoutAnimationзначение · refFLIP-анимация этого списка; по умолчанию — animation провайдера. Значение или ref (функция — это своя анимация).
AutoAnimationзначение · ref · геттерАнимирует изменения items, сделанные не драгом: добавленные, удалённые, перемещённые и отфильтрованные элементы (см. AutoAnimation). По умолчанию — animateChanges провайдера; выключено, если там не задано. Читается при изменении items.
booleanзначение · ref · геттерСобственный размер списка следует за его элементами: когда драг приносит элемент в список или уносит из него (а также при броске и при изменениях, которые показывает animateChanges), список растёт или сжимается до нового размера с длительностью и easing из animation, а не скачком, и то, что вокруг, сдвигается вместе с ним. По умолчанию true; false оставляет скачок. Читается при каждом изменении.
boolean | AutoScrollOptionsзначение · ref · геттерПереопределяет autoScroll провайдера для скролл-контейнера этого списка. Читается в начале драга.
MaybeElementRefЭлемент, который принимает броски для списка; по умолчанию — сам элемент списка. Например, вся колонка вокруг короткого списка карточек: тогда карточка, отпущенная ниже последней, всё равно попадает в список (в его конец). Элементы остаются в элементе списка.
booleanзначение · ref · геттерtrue: его элементы нельзя перетащить, и он не принимает элементы.
( event: SortableDropEvent<T>, ) => MaybePromise<BeforeDropResult>Вызывается перед броском в этот список и перед тем, как dropOutside: 'remove' уберёт его элементы: false отклоняет бросок (элементы улетают обратно), список ключей принимает только эти элементы. Может быть асинхронным: оверлей ждёт там, где его отпустили. Ошибка тоже отклоняет бросок. Про result и preventDefault — см. SortableDropEvent.
(event: SortableDropEvent<T>) => voidВызывается, когда бросок в этот список принят, но ещё не записан: в items всё ещё старый порядок, в event.result — новый. Синхронный: запись следует сразу после возврата, если не был вызван event.preventDefault(). Также вызывается у списка, откуда пришли элементы, когда их удаляют (to.index равен -1).
Возвращает
Что возвращает makeSortableList.
KeyId списка: опция id или созданный для него id.
ComputedRef<T[]>Порядок черновика: рендерите его, а не исходный массив.
ComputedRef<boolean>Над списком драг.
ComputedRef<boolean>Что-то перетаскивается, и этот список это принимает.
ComputedRef<SortableIndicator | null>Режим индикатора: куда в этом списке попадёт бросок; null, если не сюда.
ComputedRef<Key | null>Строка, которую виртуализатор должен держать смонтированной: слот, пока он в этом списке (копия, созданный элемент), иначе перетаскиваемый элемент; null без драга.
ComputedRef<number>Индекс активного элемента в черновике этого списка; -1, если его здесь нет.
ComputedRef<Size | null>Размер перетаскиваемого элемента в начале драга: например, для размера виртуальной строки, которую он занимает.
() => voidАнимирует изменения раскладки, которые вызвала не библиотека (например, повторный замер виртуализатора).
Группы
Группа списка: списки, которые обмениваются элементами, и могут ли элементы покидать этот список и попадать в него.
stringСписки и деревья с одинаковым именем обмениваются элементами.
boolean | 'clone'Могут ли элементы покидать этот список: перемещением, копированием ('clone', палитра) или никак.
boolean | string | string[] | ((context: SortablePutContext<T>) => boolean)Могут ли элементы попадать в этот список: true (по умолчанию), false, тип или типы, которые должны быть у элементов (как accept цели: с acceptMode — все или некоторые), или функция от драга.
С чем вызывается group.put, заданный функцией: элементы, которые вошли бы в список.
Событие броска
Что получают onBeforeDrop и onDrop.
Бросок на сортируемый список или дерево. Его хуки выполняются по порядку: onBeforeDrop принимает решение, onDrop получает уведомление, затем действие по умолчанию записывает result в items каждого списка, который в нём указан, и оверлей приземляется. preventDefault() в любом из хуков пропускает эту запись, чтобы вы применили result сами.
Key[]Ключи перетаскиваемых элементов.
T[]Элементы, которые приземляются: перетаскиваемые, их копии (mode: 'copy') или элемент, созданный createItem ('insert').
Key[]Ключи, которые проходят: все, если только список или onBeforeDrop не принимает лишь часть.
Key[]Ключи, которые улетают обратно, туда, где были.
{ list: Key | null; index: number }Где начался драг: список и индекс активного элемента. list равен null для обычного перетаскиваемого элемента извне.
{ list: Key; index: number }index равен -1, если ничего не приземлилось: элементы покинули свои списки (e.source.remove(), dropOutside: 'remove').
booleanБросок остаётся в списке, где начался драг.
DragModeЧто делает бросок (см. DragMode).
{ key: Key; item: T; from: { list: Key; index: number }; to: { list: Key; index: number } }mode: 'swap': элемент, с которым обменялся перетаскиваемый. Он сдвинулся в обратную сторону: from — место, которое занял перетаскиваемый элемент (to выше), to — место, откуда перетаскиваемый элемент начал (from выше); между списками — в список перетаскиваемого элемента.
ReadonlyMap<Key, T[]>Новые элементы каждого списка, который меняет бросок, по id списка: ровно то, что запись по умолчанию кладёт в их items, в виде новых массивов. Сюда входят перемещения, копии, созданные элементы, частичный приём, обе стороны обмена и удалённые элементы (e.source.remove() в цели внутри элемента, зона-корзина, dropOutside: 'remove'); списка, который бросок оставляет как есть, здесь нет. Запись дерева — новый массив корней: узлы на изменённых путях — копии (withChildren), нетронутые поддеревья общие, ваши узлы никогда не мутируются. В onBeforeDrop это бросок в том виде, в каком он есть до ответа хука (если вернуть часть ключей, он изменится); onDrop получает окончательный.
() => voidПропускает запись по умолчанию — во все списки из result (запись только в некоторые потеряла бы или задублировала элементы). Примените result сами в onDrop или до того, как разрешится асинхронный onBeforeDrop, — и оверлей приземлится уже в новом порядке. Если нигде его не применить, списки остаются как были, а оверлей улетает обратно (копии и созданные элементы, у которых ещё нет места, растворяются).
booleanpreventDefault() был вызван — в onBeforeDrop или onDrop.
ExternalDataДраг извне страницы (external): что он нёс, вместе с данными (бросок состоялся).
Индикатор
Что содержит indicator в режиме placeholder: 'indicator'.
Куда попадёт бросок при placeholder: 'indicator': список не двигается, линию рисуете вы.
KeyId списка (или дерева), куда попадёт бросок.
numberПозиция вставки в списке в том виде, как он отрендерен.
Key | nullЭлемент, к которому привязан индикатор; null в пустом списке.
'before' | 'after' | 'inside' | 'swap'С какой стороны от key рисуется линия. 'inside' (деревья): драг наведён на середину строки, которая принимает перетаскиваемые узлы, и бросок идёт в неё первым дочерним узлом. 'swap' (behavior: 'swap'): key — элемент, с которым бросок поменяет местами; отмечайте сам элемент.
numberДеревья: глубина, которую получат брошенные узлы (у корней 0), например чтобы сдвинуть линию отступом.
Key | nullДеревья: родитель, которого получат брошенные узлы; null на корневом уровне.
Значения
Источник элементов сортируемого списка. Записываемый ref: библиотека записывает в него каждый бросок. Источник только для чтения (геттер, readonly ref, computed: иммутабельный стор, серверное состояние, стор, который меняется только через экшены): каждый бросок вы применяете сами из event.result после event.preventDefault() (см. SortableDropEvent).
type SortableItems = Ref<T[]> | Readonly<Ref<readonly T[]>> | (() => readonly T[])Как список раскладывает свои элементы: колонкой ('vertical'), строкой ('horizontal') или сеткой с переносом ('grid').
type SortableStrategy = 'vertical' | 'horizontal' | 'grid'Что происходит при наведении на элемент: 'sort' освобождает место (элементы между ними сдвигаются), 'swap' меняет два элемента местами.
type SortableBehavior = 'sort' | 'swap'Как драг показывает, куда он попадёт: 'item' — слот перетаскиваемого элемента движется по списку; 'indicator' — список остаётся как есть, а indicator говорит, куда попадёт бросок (линию рисуете вы).
type SortablePlaceholder = 'item' | 'indicator'Что делают остальные выделенные элементы при мульти-драге:
'group': покидают свои места и едут вместе с активным элементом сплошным рядом плейсхолдеров, поэтому при наведении список уже показывает результат броска;'gaps': остаются на местах до броска;'stack': схлопываются в оверлей.
Стандартный оверлей показывает перетаскиваемые элементы столбиком вдоль списка ('group', 'gaps'; строкой в горизонтальных списках, стопкой за активным в сетках) или активный элемент со счётчиком ('stack').
type MultipleMode = 'group' | 'gaps' | 'stack'Что делает бросок вне всех целей: 'placeholder' оставляет элементы там, где их слот, 'cancel' возвращает их обратно, 'remove' убирает их из списка.
type DropOutside = 'placeholder' | 'cancel' | 'remove'