function makeSortableList<T>( target: MaybeElementRef, options: SortableListOptions<T>,): SortableListReturn<T>;컨테이너를 정렬 가능한 리스트로 만듭니다. 원본 배열이 아니라 반환된 items(초안 순서)를 렌더링하세요. 드롭 결과는 onDrop 다음에 options.items에 다시 기록됩니다. 단, 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의 옵션. 컴포넌트 하나가 리스트(와 트리)를 여러 개 만들 수 있습니다. 그 안에서 렌더링되는 각 항목은 자신을 감싸는 요소를 가진 가장 안쪽 리스트에 들어갑니다.
옵션은 값, ref, getter를 받으며(overlay, overOverlay, dropAnimation, overDropAnimation, animation: 값 또는 ref) 리스트가 필요할 때 읽으므로, 변경은 늦어도 다음 드래그부터 적용됩니다. 예외: id와 group은 리스트가 만들어질 때 한 번만 읽습니다. items는 모델 자체입니다. 함수(getKey, filter, clone, createItem, 콜백)는 그대로 넘깁니다.
SortableItems<T>단일 진실 공급원. 쓰기 가능한 ref는 드롭할 때 onDrop 바로 다음에 새 배열을 받습니다. 읽기 전용 소스(getter, readonly ref, computed)는 받을 수 없으므로 event.preventDefault()를 호출하고 event.result를 직접 적용하세요. 개발 빌드에서는 이런 경우 드롭을 라이브러리에 맡기면 경고하며, 이때는 아무것도 바뀌지 않습니다.
(item: T) => Key기본값: item.id, 원시값이면 항목 자체. makeSortableItem({ item })의 key도 이것으로 정합니다.
(item: T) => booleantrue를 반환한 항목만 보여 줍니다(검색, 태그). 반환되는 items에는 그 항목들만 있고, 드래그는 그 안에서 정렬합니다. 나머지 항목은 원본에서 자기 자리를 유지합니다. 드롭은 배열 전체를 기록하며, 숨겨진 각 항목은 원래 뒤따르던 보이는 항목 뒤에 그대로 남습니다(그 항목이 옮겨졌다면 남아 있는 가장 가까운 항목 뒤). 반응형: 함수가 읽는 것(검색어 ref)은 바로 적용됩니다. e.to.index와 activeIndex는 보이는 항목을 기준으로 셉니다.
Key기본값: useId(). 서버 렌더링과 클라이언트 렌더링 사이에서 안정적입니다. 한 번만 읽습니다.
string값 · ref · getter사람이 리스트를 부르는 이름. 스크린 리더용 문구가 id 대신 이 이름을 읽습니다(position 2 of 5 in Garden).
unknown값 · ref · getter드롭 대상으로서의 리스트에 대해 알릴 아무 데이터. 드래그가 위에 있는 동안 이벤트는 이것을 over.data로 담습니다.
ActivationOptions값 · ref · getter이 리스트의 항목을 눌렀을 때 드래그가 시작되는 방식으로, 프로바이더의 activation 대신 쓰입니다(항목 자체의 설정이 우선합니다). 누르기가 시작될 때 읽습니다.
Component값 · ref이 리스트 항목의 오버레이 컴포넌트(항목 자체의 overlay가 우선합니다). OverlayProps를 받으며, 다른 리스트 위에서도 드래그가 끝날 때까지 유지됩니다. 단, 드래그 아래의 대상에 자체 오버레이(overOverlay)가 있으면 예외입니다. 드래그 중에 바꾼 ref는 바로 교체됩니다.
Component값 · ref이 리스트가 받는 드래그가 위에 있는 동안, 어느 리스트에서 왔든 오버레이가 보여 줄 것. OverlayProps와 드래그 자체의 오버레이를 기본 슬롯으로 받는 컴포넌트입니다(DroppableOptions.overOverlay 참고). 실시간으로 읽습니다.
DropAnimation값 · ref이 리스트 항목의 드래그가 끝날 때 오버레이가 안착하는 방식으로, 프로바이더의 dropAnimation 대신 쓰입니다(항목 자체의 것이 우선하고, 드롭 대상의 것은 둘 모두보다 우선합니다). 드롭할 때 읽습니다.
DropAnimation값 · ref어느 리스트에서 왔든 이 리스트에 드롭될 때 오버레이가 안착하는 방식. 드래그 중인 항목과 프로바이더의 dropAnimation보다 우선합니다. 드롭할 때 읽습니다.
Modifier[]값 · ref · getter이 리스트 항목의 드래그에 적용할 모디파이어. 프로바이더의 modifiers 다음에 적용됩니다(항목 자체의 modifiers가 우선합니다). 예: 세로 리스트의 항목을 축 위에 두는 [restrictToVerticalAxis]. 드래그가 시작될 때 읽습니다.
'x' | 'y'값 · ref · getter이 리스트 항목의 드래그를 한 축에 고정합니다. 세로 리스트에는 'y', 가로 리스트에는 'x'(항목 자체의 axis가 우선합니다). 고정은 모디파이어 다음에 적용되므로, 모디파이어가 무엇을 하든 유지됩니다. 드래그가 시작될 때 읽습니다.
string | SortableGroupOptions<T>그룹 이름이 같은 리스트끼리 항목을 주고받습니다. 기본값: 별도의 그룹. 한 번만 읽습니다.
AcceptMode값 · ref · getter여러 타입의 항목을 멀티 드래그할 때: 'all'(기본값) 또는 'some'이 수락되어야 합니다(group.put).
SortableStrategy값 · ref · getter기본값 'vertical'.
SortableBehavior값 · ref · getter'swap': 드래그한 항목이 포인터 아래 항목과 실시간으로 자리를 맞바꿉니다. 그 항목 위로 되돌아가거나 리스트 밖으로 나가면 원래대로 돌아갑니다. 같은 그룹에서 둘 다 맞바꾸는 리스트는 서로 항목을 주고받습니다. 포인터 아래 항목이 드래그한 항목의 자리로 옮겨 가므로, 그 항목은 자기 리스트를 떠날 수 있어야 하고(group.pull: true) 드래그한 항목의 리스트에 들어갈 수 있어야 합니다(group.put). 멀티 드래그는 대신 정렬합니다. 기본값 'sort'.
SortablePlaceholder값 · ref · getter'indicator': 리스트가 움직이지 않고, indicator가 드롭될 위치를 알려 줍니다. 기본값 'item'.
MultipleMode값 · ref · getter이 리스트에서 시작하는 드래그의 멀티 드래그 모드. 기본값 'group'. 드래그가 시작될 때 읽습니다.
boolean값 · ref · getterfalse: 이 리스트 안에서는 항목의 순서를 바꿀 수 없습니다(팔레트).
(item: T) => T복사본을 만듭니다(pull: 'clone', 복사 모디파이어 키). 복사하려면 필수입니다.
(active: Active) => T | T[]외부의 일반 draggable을 받아들입니다. 삽입할 항목을 만듭니다. 키보드에서는 리스트 쪽 화살표 키를 누르면 draggable이 (리스트 사이 이동처럼 같은 높이로) 리스트에 들어가고, 만들어진 항목은 다른 항목처럼 자리 단위로 움직입니다.
페이지 밖에서 온 드래그(external)에 대해서는 두 번 호출됩니다. 드래그하는 동안에는 어디로 갈지 보여 주는 항목을 위해(이때는 active.external.fileTypes와 types만 알 수 있습니다), 드롭할 때는 데이터와 함께(active.external.ready) 삽입할 것을 위해서입니다. 항목 배열을 반환하면 모두 자리가 있던 곳에 삽입됩니다. 파일마다 하나씩입니다.
ExternalAccept값 · ref · getter페이지 밖에서 오는 드래그를 받습니다. 파일, 링크, 텍스트(ExternalAccept 참고). 리스트는 일반 draggable과 마찬가지로 createItem으로 자리를 만들며, 그래서 createItem이 필요합니다. 앱의 다른 창에서 끌어온 같은 그룹의 항목(native)에는 두 옵션 모두 필요 없습니다. 항목 자체로 들어옵니다. 값, ref 또는 getter이며 실시간으로 읽습니다.
DropOutside값 · ref · getter모든 대상 바깥에 드롭할 때: 플레이스홀더가 있는 곳에 항목을 두거나, 취소하거나, 제거합니다. 기본값 'placeholder'(placeholder: 'indicator'일 때는 'cancel'). 드롭할 때 읽습니다.
LayoutAnimation값 · ref이 리스트의 FLIP 애니메이션. 기본값: 프로바이더의 animation. 값 또는 ref(함수는 커스텀 애니메이션입니다).
AutoAnimation값 · ref · getter드래그가 아닌 items 변경을 애니메이션합니다: 추가, 제거, 이동, 필터링된 항목(AutoAnimation 참고). 기본값: 프로바이더의 animateChanges. 프로바이더에서 설정하지 않으면 꺼져 있습니다. items가 바뀔 때 읽습니다.
boolean값 · ref · getter리스트 자체의 크기가 항목을 따라갑니다. 드래그가 항목을 들여오거나 내보낼 때(그리고 드롭할 때와 animateChanges가 보여 주는 변경에서도), 리스트는 한 번에 바뀌지 않고 animation의 지속 시간과 이징으로 새 크기까지 커지거나 줄어들며, 주변의 것도 함께 움직입니다. 기본값 true. false이면 한 번에 바뀝니다. 변경될 때마다 읽습니다.
boolean | AutoScrollOptions값 · ref · getter이 리스트의 스크롤 컨테이너에 대해 프로바이더의 autoScroll을 재정의합니다. 드래그가 시작될 때 읽습니다.
MaybeElementRef리스트 대신 드롭을 받는 요소. 기본값은 리스트 요소 자체입니다. 예: 짧은 카드 리스트를 둘러싼 컬럼 전체. 이렇게 하면 마지막 카드 아래에서 놓은 카드도 리스트(의 끝)에 안착합니다. 항목은 리스트 요소 안에 그대로 있습니다.
boolean값 · ref · gettertrue: 항목을 드래그할 수 없고, 항목을 받지도 않습니다.
( event: SortableDropEvent<T>, ) => MaybePromise<BeforeDropResult>이 리스트로 드롭하기 전, 그리고 dropOutside: 'remove'가 항목을 빼기 전에 호출됩니다. false는 거부하고(항목은 원래 자리로 돌아갑니다), 일부 key는 해당 항목만 수락합니다. 비동기일 수 있으며, 이때 오버레이는 드롭한 자리에서 기다립니다. 에러가 발생해도 드롭이 거부됩니다. result와 preventDefault는 SortableDropEvent를 참고하세요.
(event: SortableDropEvent<T>) => void이 리스트로의 드롭이 수락되면, 기록되기 전에 호출됩니다. items는 아직 이전 순서이고 event.result에 새 순서가 있습니다. 동기 함수입니다. event.preventDefault()를 호출하지 않았다면 반환 직후 기록이 이어집니다. 항목이 제거될 때는 항목이 온 리스트에서도 호출됩니다(to.index는 -1).
반환값
makeSortableList가 반환하는 것.
Key리스트의 id: 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[]드래그된 항목의 key.
T[]안착하는 항목: 드래그된 항목, 그 복사본(mode: 'copy'), 또는 createItem이 만든 항목('insert').
Key[]확정되는 key: 전부입니다. 리스트나 onBeforeDrop이 일부만 받은 경우는 예외입니다.
Key[]원래 자리로 돌아가는 key.
{ list: Key | null; index: number }드래그가 시작된 곳: 활성 항목의 리스트와 인덱스. 외부에서 온 일반 draggable이면 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에서는 훅이 응답하기 전 상태의 드롭이며(일부 key를 반환하면 바뀝니다), onDrop은 최종 결과를 받습니다.
() => voidresult의 모든 리스트에 대한 기본 기록을 건너뜁니다(일부에만 기록하면 항목이 사라지거나 중복됩니다). onDrop에서, 또는 비동기 onBeforeDrop이 resolve되기 전에 result를 직접 적용하면 오버레이가 새 순서대로 안착합니다. 어디에도 적용하지 않으면 리스트는 그대로이고 오버레이는 원래 자리로 돌아갑니다(아직 자리가 없는 복사본과 새로 만든 항목은 서서히 사라집니다).
booleanonBeforeDrop 또는 onDrop에서 preventDefault()가 호출되었습니다.
ExternalData페이지 밖에서 온 드래그(external)가 담고 있던 것. 데이터도 들어 있습니다(이미 드롭되었습니다).
인디케이터
placeholder: 'indicator' 모드에서 indicator에 담기는 값입니다.
placeholder: 'indicator'일 때 드롭할 곳: 리스트는 움직이지 않고, 선은 직접 그립니다.
Key드롭이 들어갈 리스트(또는 트리)의 id.
number렌더링된 리스트 기준의 삽입 위치.
Key | null인디케이터가 붙은 항목. 빈 리스트에서는 null.
'before' | 'after' | 'inside' | 'swap'선이 들어갈 key의 방향. 'inside'(트리): 드래그 중인 노드를 받아들이는 행의 가운데에 포인터가 있으며, 드롭이 그 행 안의 첫 번째 자식으로 들어갑니다. 'swap'(behavior: 'swap'): key는 드롭이 자리를 맞바꿀 항목입니다. 항목 자체를 표시하세요.
number트리: 드롭된 노드가 갖게 될 깊이(루트는 0). 예: 선 들여쓰기.
Key | null트리: 드롭된 노드가 갖게 될 부모. 루트 단계에서는 null.
값
정렬 가능한 항목의 소스. 쓰기 가능한 ref: 라이브러리가 드롭마다 기록합니다. 읽기 전용 소스(getter, readonly ref, computed: 불변 스토어, 서버 상태, 액션으로만 바꾸는 스토어): event.preventDefault() 다음에 event.result로 드롭마다 직접 적용합니다(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'