Dokumentation/API
DnDProvider
Die Komponente, die den Drag verantwortet – Eingabe, Overlay, Auswahl, Auto-Scroll und die Live-Region – für alles, was in ihr gerendert wird.
Diese Seite wurde von KI übersetzt und kann Ungenauigkeiten enthalten. Englisches Original lesen
const DnDProvider: Component<DnDProviderProps>;Verwaltet die Drags von allem, was darin gerendert wird: Eingabe, Overlay, Auswahl, Auto-Scroll und die Screenreader-Ansagen (siehe DnDProviderProps).
<script setup lang="ts">
import { DnDProvider } from '@vue-dnd-kit/core';
</script>
<template>
<DnDProvider :animation="{ duration: 200 }" @drag-end="save">
<RouterView />
<template #overlay="{ items, over, accepted }">
<!-- optional: a custom overlay for every drag -->
</template>
</DnDProvider>
</template>
Jedes Composable muss in einer Komponente laufen, die innerhalb eines Providers gerendert
wird. Ziel ist ein einziger Provider für die ganze App: Teile der Seite bekommen mit
makeDragArea eigene Regeln. Siehe den Leitfaden
Der Provider.
Die meisten Props werden gelesen, wenn der Provider sie braucht: Ändere eine, und der nächste Drag verwendet sie.
Demo wird geladen…
<script setup lang="ts">
import { computed, ref } from 'vue';
import { DnDProvider, type ActivationOptions } from '@vue-dnd-kit/core';
import PropRow from './PropRow.vue';
import DensityList from './DensityList.vue';
const ACTIVATIONS: Record<string, ActivationOptions | undefined> = {
default: undefined,
'{ mouse: { delay: 300 } }': { mouse: { delay: 300, tolerance: 5 } },
};
const overlayFit = ref<'slot' | 'source'>('slot');
const activation = ref('default');
const keyboard = ref<'true' | 'false'>('true');
const copyModifier = ref<'Alt' | 'Shift' | 'null'>('Alt');
// The provider reads its props when it needs them: a change applies to the next drag.
const props = computed(() => ({
overlayFit: overlayFit.value,
activation: ACTIVATIONS[activation.value],
// `false` turns keyboard drags off; an object sets their keys and steps.
keyboard: keyboard.value === 'true' ? undefined : (false as const),
copyModifier: copyModifier.value === 'null' ? null : copyModifier.value,
}));
const compact = ref([
{ id: 'copy', title: 'Write copy' },
{ id: 'login', title: 'Fix login' },
]);
const roomy = ref([
{ id: 'sprint', title: 'Plan the sprint' },
{ id: 'review', title: 'Review the PR' },
]);
</script>
<template>
<DnDProvider v-bind="props">
<div class="demo">
<div class="props" role="group" aria-label="DnDProvider props">
<PropRow v-model="overlayFit" name="overlay-fit" :options="['slot', 'source']" />
<PropRow v-model="activation" name=":activation" :options="Object.keys(ACTIVATIONS)" />
<PropRow v-model="keyboard" name=":keyboard" :options="['true', 'false']" />
<PropRow v-model="copyModifier" name="copy-modifier" :options="['Alt', 'Shift', 'null']" />
</div>
<div class="lists">
<DensityList v-model="compact" title="Compact" compact />
<DensityList v-model="roomy" title="Roomy" />
</div>
</div>
</DnDProvider>
</template>
<style scoped>
/* Room for every row in one list: the lists grow downward and nothing moves under the pointer. */
.demo {
display: flex;
flex-direction: column;
align-items: center;
gap: 18px;
min-height: 430px;
}
.props {
display: grid;
grid-template-columns: auto auto;
align-items: center;
gap: 6px 14px;
max-width: 100%;
padding: 12px 14px;
border: 1px solid color-mix(in srgb, currentColor 12%, transparent);
border-radius: 12px;
background: color-mix(in srgb, currentColor 3%, Canvas);
}
.lists {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
justify-content: center;
gap: 14px;
}
@media (max-width: 480px) {
.props {
grid-template-columns: minmax(0, 1fr);
}
}
</style>Wo das Overlay gerendert wird
overlayTo holt das Overlay aus body heraus: in ein modales <dialog>, das über allem anderen
auf der Seite liegt. Schalte den Schalter aus, und die Zeilen, die du ziehst, verschwinden unter
dem Dialog. Der Overlay-Leitfaden erklärt,
wann das nötig ist.
Demo wird geladen…
<script setup lang="ts">
import { computed, ref, useTemplateRef } from 'vue';
import { DnDProvider } from '@vue-dnd-kit/core';
import ColumnList from './ColumnList.vue';
const columns = ref(['Name', 'Status', 'Owner', 'Due date', 'Priority']);
const dialog = useTemplateRef<HTMLDialogElement>('dialog');
const open = ref(false);
const intoDialog = ref(true);
// A modal <dialog> sits on the top layer, above everything in <body>, the overlay
// included. While it is open, the overlay renders inside it.
const overlayTo = computed(() => (open.value && intoDialog.value ? '#columns-dialog' : 'body'));
const show = () => {
dialog.value?.showModal();
open.value = true;
};
</script>
<template>
<DnDProvider :overlay-to="overlayTo">
<div class="sheet">
<table>
<thead>
<tr>
<th v-for="column in columns" :key="column">{{ column }}</th>
</tr>
</thead>
<tbody>
<tr v-for="row in 2" :key="row">
<td v-for="column in columns" :key="column"><span class="skeleton" /></td>
</tr>
</tbody>
</table>
<button type="button" class="primary" @click="show">Edit columns</button>
</div>
<dialog id="columns-dialog" ref="dialog" @close="open = false">
<h3>Columns</h3>
<p>Drag to change their order.</p>
<ColumnList v-model:columns="columns" />
<footer>
<label class="switch">
<input v-model="intoDialog" type="checkbox" />
Overlay inside the dialog
</label>
<button type="button" class="primary" @click="dialog?.close()">Done</button>
</footer>
</dialog>
</DnDProvider>
</template>
<style scoped>
.sheet {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
width: 100%;
}
table {
width: min(100%, 520px);
border-collapse: collapse;
font-size: 12px;
}
th {
padding: 8px;
border-bottom: 1px solid color-mix(in srgb, currentColor 15%, transparent);
font-weight: 600;
text-align: left;
white-space: nowrap;
}
td {
padding: 10px 8px;
border-bottom: 1px solid color-mix(in srgb, currentColor 8%, transparent);
}
.skeleton {
display: block;
height: 8px;
border-radius: 4px;
background: color-mix(in srgb, currentColor 10%, transparent);
}
button {
padding: 7px 14px;
border: 0;
border-radius: 8px;
font: 600 12px/1.2 system-ui, sans-serif;
cursor: pointer;
}
.primary {
background: #42b883;
color: #04130c;
}
button:focus-visible {
outline: 2px solid #42b883;
outline-offset: 2px;
}
/* No transform on the dialog: it would move the overlay's fixed position. */
dialog {
width: min(340px, calc(100vw - 32px));
box-sizing: border-box;
margin: auto;
padding: 18px;
border: 1px solid color-mix(in srgb, currentColor 14%, transparent);
border-radius: 16px;
background: Canvas;
color: CanvasText;
box-shadow: 0 30px 60px -20px rgb(0 0 0 / 0.6);
}
dialog::backdrop {
background: rgb(0 0 0 / 0.45);
}
h3 {
margin: 0;
font-size: 15px;
}
p {
margin: 4px 0 14px;
font-size: 12px;
opacity: 0.6;
}
footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-top: 16px;
}
.switch {
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
}
.switch input {
accent-color: #42b883;
}
</style>Props
Props von DnDProvider. Die meisten werden gelesen, wenn der Provider sie braucht: Ändere eine, und der nächste Drag verwendet sie.
CollisionDetectionWie das Ziel unter dem Drag gewählt wird. Standard pointerFirst; eine andere eingebaute (closestCorners) oder deine eigene.
Modifier[]Modifier für jeden Drag, zuerst angewendet: Die von Drag-Bereichen, ziehbaren Elementen und Listen kommen danach.
LayoutAnimationStandard-FLIP-Animation für sortierbare Listen.
DropAnimationWie das Overlay beim Drop landet und beim Abbrechen zurückfliegt, wenn nichts Näheres eine setzt: Zuerst kommt die overDropAnimation des Drop-Ziels, dann die eigene des gezogenen Elements (oder die seiner Liste), dann diese.
AutoAnimationStandardwert von animateChanges für sortierbare Listen und Bäume: Änderungen ihrer Elemente, die kein Drag ausgelöst hat. Standardmäßig aus.
boolean | AutoScrollOptionsScrollt Container und die Seite, wenn sich ein Drag ihren Rändern nähert. Standard true; Optionen stimmen es ab, false schaltet es aus. Listen, Bäume und Drag-Bereiche können es überschreiben.
ActivationOptionsWas ein Drücken tun muss, bevor es zum Drag wird, pro Zeigerart (Standardwerte siehe ActivationOptions). Drag-Bereiche, Listen, Bäume, Elemente und ziehbare Elemente können es überschreiben.
KeyboardOptions | falseZiehen per Tastatur: Tasten und Schrittweite. false schaltet es aus; Escape bricht trotzdem jeden Drag ab.
Sensor[]Was Eingaben zu Drags macht. Standard [pointerSensor, keyboardSensor]: Lass einen weg, umhülle oder ersetze ihn oder füge eigene hinzu (defineSensor). Der Tastatursensor bricht außerdem jeden Drag mit Escape ab; keyboard: false schaltet seine Drags aus, behält das aber bei. Die Liste kann sich jederzeit ändern: Sensoren, die sie verlassen, stoppen und brechen dabei ihren Drag ab.
boolean | HapticsOptionsVibration für Drags per Touch. Standard: eine kurze, wenn ein Drag nach dem langen Drücken beginnt; ein Objekt fügt weitere hinzu (enter, drop, refuse); false schaltet alle aus.
string | nullTaste (KeyboardEvent.key), die eine Verschiebung in eine Kopie verwandelt. Standard 'Alt'; null deaktiviert das.
string | HTMLElementWo das Overlay gerendert wird: ein Selektor oder ein Element. Standard 'body'. Ein modaler <dialog> liegt über dem Rest der Seite: Drags darin brauchen es dort.
'slot' | 'source'Größe des Overlays während des Ziehens. 'slot' (Standard): Das Overlay folgt dem Slot, in dem das Element landen wird; über einer anderen Liste nimmt es also die Größe der Elemente dieser Liste an, und der Drop braucht keine Größenänderung. Es ändert seine Größe um den Zeiger herum, der immer beim selben Anteil der Box bleibt. 'source': Es behält die Größe des gezogenen Elements. Der Inhalt des Standard-Overlays wird in der neuen Größe neu angeordnet; er wird nie skaliert.
number | 'all'Multi-Drag: wie viele gezogene Elemente beim Aufnehmen einen Klon bekommen, das gegriffene und die anderen daneben in Drop-Reihenfolge. Standard 5; 'all' klont jedes, das gerendert ist. Das Standard-Overlay zeigt die Klone und zählt den Rest (+N); in einem eigenen Layout rendert DragPreview für ein Element ohne Klon seinen Slot. Jeder Klon fliegt: bei einem Abbruch zurück zu seinem Element, bei einem Drop zu seinem Slot, in die Zone, in die ein Drop geht, einer nach dem anderen. Die Klone werden gemeinsam erstellt, mit einem Layout pro Snapshot-Durchlauf für alle, aber jeder kostet das Auslesen seiner Styles: Achte auf lange Elemente auf langsamen Handys.
boolean | TransitionPropsWie das Overlay während eines Drags von einer Komponente zur anderen wechselt (das overOverlay eines Drop-Ziels übernimmt, ein overlay-Ref wird umgeschaltet): true (Standard) blendet sie in 150 ms über, false tauscht sie sofort, und ein Objekt sind die Props einer Vue-<Transition> um die Wurzel des Inhalts (name, mode, JS-Hooks für GSAP oder motion). Ohne mode: 'out-in' sind beide gleichzeitig zu sehen: Gib der ausgehenden position: absolute (.<name>-leave-active), damit sie sich in der Box stapeln.
string | Record<string, boolean> | Array<string | Record<string, boolean>>Klassen für den Inhalt des Overlays ([data-dnd-overlay-content]), das Element, das die Overlay-Box füllt: das, das als Ganzes animiert wird, während die Bibliothek die Box bewegt und ihre Größe setzt. Eine Transition darauf läuft beim Aufnehmen von @starting-style aus und beim Landen zurück ([data-dnd-overlay='dropping']): Der Drop wartet auf sie. Einfaches CSS erreicht es außerhalb von <style scoped> (oder mit :global(...)), Tailwind mit starting: und in-data-[dnd-overlay=dragging]:.
Partial<Announcements> | falseEigene Texte für einige Events (siehe Announcements); false lässt die Live-Region stumm.
stringWie man per Tastatur zieht, von Screenreadern für jedes ziehbare Element vorgelesen (sein aria-describedby). Standard: englische Anweisungen für Leertaste, Enter, die Pfeiltasten und Escape.
booleanDas Standard-Aussehen einfügen: CSS ohne Spezifität in Layern, das Platzhalter und die Elemente, die ein Multi-Drag an ihrem Platz lässt, abblendet (opacity: 0.4). Standard true; false überlässt das Aussehen dir. Was Drags brauchen, wird in jedem Fall eingefügt: keine Textauswahl und kein Scroll-Anchoring während des Ziehens (virtuelle Listen sind darauf angewiesen), der Drag-Cursor (--dnd-cursor) und kein Link-Callout bei langem Drücken auf iOS.
Events
| Event | Payload | Wann |
|---|---|---|
drag-start | DnDEvent | Ein Drag hat begonnen (nach seiner Aktivierung). |
drag-move | DnDEvent | Der Zeiger hat sich während eines Drags bewegt (höchstens einmal pro Frame). |
drag-over | DnDEvent | Das Ziel unter dem Drag hat sich geändert. |
drag-end | DnDEndEvent | Ein Drop wurde ausgeführt und geschrieben. |
drag-cancel | DnDEvent | Der Drag wurde abgebrochen oder der Drop abgelehnt. |
drag-resume | DnDEvent | onBeforeDrop hat 'continue' geantwortet: Es gab keinen Drop, und der Drag geht weiter. |
drag-settle | DnDEndEvent oder DnDEvent | Das Overlay des Drags ist gelandet: das, was drag-end oder drag-cancel bekommen hat. |
Dieselben Events, dazu onBeforeDrop, stehen mit
useDnDMonitor überall unterhalb des Providers zur Verfügung. Ihre Payloads
findest du unter Events.
Slot #overlay
Rendert, was dem Zeiger folgt, für jeden Drag ohne eigene Overlay-Komponente (siehe den Leitfaden Das Overlay). Rendert der Slot nichts, kommt der Klon zum Einsatz.
Was das Overlay zeigt: die Props des Slots #overlay des Providers und von Overlay-Komponenten (Option overlay von ziehbaren Elementen, sortierbaren Elementen, Listen und Bäumen).
ActiveDer Drag.
DragItem[]Alle gezogenen Elemente, das primäre zuerst: ein Overlay für den ganzen Multi-Drag.
Over | nullDas Drop-Ziel unter dem Drag. Während ein entschiedener Drop animiert wird, das Ziel, auf dem er landet (so, wie es beim Drop war); null, während ein abgebrochener Drag zurückfliegt.
booleanOb over die gezogenen Elemente annimmt; false, wenn der Drag über nichts ist.
DnDStatus'dragging', dann 'dropping', während das Overlay landet (oder zurückfliegt).
DragModeWas ein Drop jetzt bewirken würde (siehe DnDEvent.mode): z. B. ein Plus zeigen, solange er kopiert.
DropDestination | nullWohin ein Drop die gezogenen Elemente jetzt legen würde, in einer sortierbaren Liste oder einem Baum: z. B. um das Overlay nach dem Ordner zu färben, in den ein Drag im Baum käme. Außerhalb aller Ziele ist es der Platz des Slots, an dem dropOutside: 'placeholder' (der Standard) sie lässt. null, wenn der Drop sie in keine Liste legen würde: über einem einfachen Drop-Ziel, über einer Liste, die sie ablehnt, außerhalb mit dropOutside: 'cancel' oder 'remove'. Während ein entschiedener Drop animiert wird, der Platz, auf dem er landet.
Tastatur
Ziehen per Tastatur (keyboard des Providers): die Tasten und die Schrittweite freier Drags.
{ start?: string[]; drop?: string[]; cancel?: string[] }Die Tasten, die aufnehmen (start), ablegen und abbrechen, als KeyboardEvent.code ('Space', 'KeyW') oder .key ('Enter', 'w'). Standard: Leertaste und Enter nehmen auf und legen ab, Escape bricht ab. Die Pfeiltasten bewegen immer.
numberPixel pro Druck auf eine Pfeiltaste bei freien (nicht sortierbaren) Drags. Standard 25.
Auto-Scroll
Wie Container scrollen, wenn sich ein Drag ihren Rändern nähert (autoScroll des Providers).
numberRandzone als Bruchteil der Containergröße. Standard 0.2 (begrenzt auf 24–96px).
numberHöchstgeschwindigkeit in px pro Frame von 16ms.
numberGeschwindigkeit in px pro Frame, wenn der Zeiger am Rand des Containers ist: langsamer innerhalb der Randzone, schneller jenseits des Rands, bis zu maxSpeed. Standard 10.
Haptik
Wann Drags per Touch vibrieren. Das tun nur Drags, die per Touch gestartet wurden; wo der Browser nicht vibrieren kann (iOS Safari) oder es blockiert (noch kein Tippen auf der Seite), passiert nichts.
HapticPatternDer Drag beginnt, nach dem langen Drücken. Standard true.
HapticPatternDer Drag betritt ein Drop-Ziel (eine Liste, eine Drop-Zone), das ihn annimmt. Standard false.
HapticPatternDer Drop wird ausgeführt. Standard false.
HapticPatternDer Drop wird abgelehnt (von einem Ziel oder von onBeforeDrop), und die Elemente fliegen zurück. Standard false.
Eine Vibration (navigator.vibrate): ihre Länge in ms oder ein Ein/Aus-Muster. true ist die Standardvibration (10ms; [20, 40, 20] für refuse), false oder 0 keine.
type HapticPattern = boolean | number | number[]Ansagen
Texte für Screenreader, pro Event. Gib undefined für den eingebauten Text zurück, '' für keinen. context enthält die Positionen, die die eingebauten Texte sortierbarer Listen sprechen.
Ein Text wird von der Live-Region des Providers gesprochen (Bewegungen, sobald der Drag 500 ms ruht); undefined überlässt das Event der nächsten Quelle (den Texten von Integrationen wie sortierbaren Positionen, dann den Standardtexten). Für das beim Aufnehmen gefundene Ziel wird keine Bewegung angesagt: Es hat sich noch nichts bewegt.
(event: DnDEvent, context: AnnouncementContext) => string | undefinedEin Drag hat begonnen.
(event: DnDEvent, context: AnnouncementContext) => string | undefinedDer Drag ist über ein anderes Ziel oder an einen anderen Platz in einer Liste gelangt (sobald er 500 ms ruht).
(event: DnDEndEvent, context: AnnouncementContext) => string | undefinedDer Drop ist durchgegangen, oder der Drag endete außerhalb aller Ziele.
(event: DnDEvent, context: AnnouncementContext) => string | undefinedDer Drag wurde abgebrochen oder sein Drop abgelehnt.
(event: DnDEvent, context: AnnouncementContext) => string | undefinedonBeforeDrop hat 'continue' geantwortet: Der Drag geht weiter.
Worum es in einer Ansage geht, über das Event hinaus: für eigene Texte (eine andere Sprache, andere Worte), die sagen, was die eingebauten sagen.
AnnouncedPositionIn einer sortierbaren Liste oder einem Baum: wo die gezogenen Elemente sind. Am Anfang, wo sie aufgenommen wurden; während der Bewegung, wo sie landen würden (keine außerhalb der Listen); am Ende, wo sie gelandet sind oder wohin sie zurückgekehrt sind.
{ key: Key; label?: string; position: AnnouncedPosition }Ein Tausch: das Element, mit dem das gezogene getauscht wurde, und wo es jetzt ist.
numberWie viele Elemente der Drag trägt.
booleanDer Drag kopiert (group.pull: 'clone', die Kopier-Taste).
Ein Platz in einer sortierbaren Liste oder einem Baum (unter seinen sichtbaren Zeilen): index zählt ab 0, von length.