Dokumentation/Leitfäden
Achsen, Grenzen und Raster
Sperre Drags auf eine Achse, halte sie in einer Box, lass sie an einem Raster oder an eigenen Hilfslinien einrasten – für ein Element, eine Liste oder einen ganzen Teil der Seite.
Diese Seite wurde von KI übersetzt und kann Ungenauigkeiten enthalten. Englisches Original lesen
Ein Drag lässt sich auf einer Achse halten, in einer Box halten, an einem Raster einrasten oder durch eine eigene Regel beugen. Die Regeln sind Modifier: Sie passen in jedem Frame den Versatz des Drags an. Setz sie an einem ziehbaren Element, an einer Liste oder an einem Teil der Seite, und das Overlay, die Drop-Ziele und der Drop folgen ihnen.
Eine Achse sperren
Clips auf einer Zeitleiste gleiten entlang ihrer Spur. Schalte die Sperre aus, und sie können auch die Spur wechseln.
Demo wird geladen…
<script setup lang="ts">
import { DnDProvider } from '@vue-dnd-kit/core';
import Timeline from './Timeline.vue';
</script>
<template>
<DnDProvider>
<Timeline />
</DnDProvider>
</template>const { isDragging } = makeDraggable(el, {
id: () => props.clip.id,
axis: () => (props.locked ? 'x' : undefined),
});
axis: 'x' bewegt nur horizontal, 'y' nur vertikal. makeDraggable, makeSortableList,
makeSortableTree, makeSortableItem und makeDragArea nehmen es alle:
makeSortableList(listRef, { items: tracks, axis: 'y' });
- Die Sperre läuft nach jedem Modifier, sie hält also, was auch immer diese tun: Ein Einrasten oder eine Grenze kann das Element nicht von seiner Linie schieben.
- Die Linie liegt im Inhalt, nicht auf dem Bildschirm: Sie bewegt sich mit der Liste (oder dem Elternelement), in der der Drag gestartet ist. Scrollst du die Seite mitten im Drag, bleibt das Element in seiner Zeile.
- Die eigene
axiseines Elements gewinnt gegen die seiner Liste oder seines Baums, und die eines ziehbaren Elements (oder seiner Liste) gegen die seines Drag-Bereichs. - Sie wird beim Start eines Drags gelesen, ein Getter kann sie also umschalten, wie oben.
- Ein auf
'y'gesperrter Baum verschachtelt trotzdem: Die Tiefe kommt dann vom Halten über der Mitte einer Zeile.
axis als die Modifier restrictToVerticalAxis und restrictToHorizontalAxis. Sie
tun dasselbe, laufen aber als gewöhnliche Modifier mitten in der Kette, und ein Modifier danach
(ein Raster, das auf beiden Achsen einrastet) kann das Element wieder von der Achse bewegen.Modifier
Ein Modifier passt in jedem Frame den Versatz des Drags an. Sein Ergebnis bewegt das Overlay
und ist der Punkt, an dem Ziele gesucht werden, also sortiert eine Liste nach der gesperrten,
begrenzten oder eingerasteten Position, und die position des Drops ist dort, wo die Box gelandet
ist.
| Modifier | Was er tut |
|---|---|
restrictToParent | Hält das Overlay in dem Container, in dem der Drag gestartet ist: der sortierbaren Liste oder dem Elternelement eines einfachen ziehbaren Elements. |
restrictToElement(target) | Hält das Overlay in einem Element: einem Template-Ref, einem Getter oder dem Element selbst. |
restrictToWindowEdges | Hält das Overlay im Fenster. |
restrictToFirstScrollableAncestor | Hält das Overlay im ersten scrollbaren Vorfahren des gezogenen Elements. |
snapToGrid(size) | Lässt das Overlay an einem Raster einrasten (unten). |
snapCenterToCursor | Zentriert das Overlay unter dem Zeiger, statt den Greifversatz zu behalten. |
restrictToVerticalAxis | Bewegt nur vertikal. Nimm lieber axis: 'y'. |
restrictToHorizontalAxis | Bewegt nur horizontal. Nimm lieber axis: 'x'. |
modifiers ist eine Option des Providers, der Drag-Bereiche, der Listen und Bäume sowie der
ziehbaren und sortierbaren Elemente. Alle außer der des Providers nehmen auch ein Ref oder einen
Getter, gelesen beim Start des Drags.
Drinnen halten
Die eigene Ansicht in einem Videocall bleibt auf dem Bildschirm. Schalte die Grenze um und ziehe sie weit hinaus:
Demo wird geladen…
<script setup lang="ts">
import { DnDProvider } from '@vue-dnd-kit/core';
import CallScreen from './CallScreen.vue';
</script>
<template>
<DnDProvider>
<CallScreen />
</DnDProvider>
</template>const { isDragging } = makeDraggable(el, {
id: 'self-view',
modifiers: () => props.modifiers, // [restrictToParent], [restrictToWindowEdges] or []
});
restrictToParenthält sie auf dem Bildschirm, ihrem Elternelement. Bei einem sortierbaren Element ist das „Elternelement“ seine Liste, wo auch immer die Liste im DOM sitzt.restrictToWindowEdgeslässt sie den Bildschirm verlassen, aber nicht das Fenster. Außerhalb des Bildschirms abgelegt, ist sie auf keinem Drop-Ziel, also fliegt sie zurück.- Ohne Grenze geht sie überallhin.
Eine Grenze hält das Overlay drinnen, in der Größe, die es hat: Mit overlayFit: 'slot' wird
eine Box, die über einer Liste breiterer Elemente wächst, in ihrer neuen Größe drinnen gehalten.
Am Raster einrasten
Die Knoten eines Flussdiagramms rasten am Raster der Zeichenfläche ein. Schalte die Zellgröße und das Gleiten um:
Demo wird geladen…
<script setup lang="ts">
import { DnDProvider } from '@vue-dnd-kit/core';
import Flowchart from './Flowchart.vue';
</script>
<template>
<DnDProvider>
<Flowchart />
</DnDProvider>
</template>const { isDragging } = makeDraggable(el, {
id: () => props.node.id,
modifiers: () => [snapToGrid({ x: props.grid, y: props.grid, smooth: props.smooth })],
});
snapToGrid(24) rastet beide Achsen auf 24-px-Zellen ein. Ein Objekt legt mehr fest:
| Option | Bedeutung |
|---|---|
x, y | Die Zellgröße in Pixeln, pro Achse. Lass eine weg, um nur die andere einrasten zu lassen: { y: 15 } rastet einen Termin auf Viertelstunden ein und lässt ihn frei über die Tage wandern. |
origin | 'container' (Standard): Die linke obere Ecke des Overlays landet auf Rasterlinien, die von der linken oberen Ecke des Containers aus gezogen sind – der sortierbaren Liste oder dem Elternelement eines einfachen ziehbaren Elements. 'delta': Der Versatz selbst wird gerundet, ein Element, das neben dem Raster gestartet ist, bleibt also neben dem Raster und bewegt sich um ganze Zellen von dort, wo es war. Nimm es für frei platzierte Elemente (eine freie Leinwand), die ihre eigene Ausrichtung behalten sollen. |
smooth | true oder { duration, easing }: Das Overlay gleitet zwischen den Zellen (standardmäßig 80 ms). Ziele nutzen die eingerastete Position sofort. |
Zeichne bei origin: 'container' das Raster ab der Border-Box des Containers: Die Zeichenfläche
oben hat ihren Rahmen als box-shadow, nicht als border, also beginnen ihre Linien direkt an
ihrem Rand.
Ein eigener Modifier
Boxen auf einer Folie springen auf die Kanten und Mitten der anderen, wenn sie nahe kommen, und pinkfarbene Hilfslinien zeigen die Linien, auf denen sie sitzen:
Demo wird geladen…
<script setup lang="ts">
import { DnDProvider } from '@vue-dnd-kit/core';
import Slide from './Slide.vue';
</script>
<template>
<DnDProvider>
<Slide />
</DnDProvider>
</template>import type { Modifier } from '@vue-dnd-kit/core';
/** Near a line, the box jumps onto it. */
const magnet: Modifier = ({ transform, overlayRect, containerRect, active }) => {
if (!containerRect) return transform;
const id = String(active.id);
const left = overlayRect.left - containerRect.left;
const top = overlayRect.top - containerRect.top;
return {
x: transform.x + pull(left, overlayRect.width, lines(id, 'x')),
y: transform.y + pull(top, overlayRect.height, lines(id, 'y')),
};
};
// In order: the magnet pulls, then the slide's edges hold.
const modifiers = [magnet, restrictToParent];
Ein Modifier bekommt transform, den Versatz zum Start des Drags, so wie ihn die Modifier davor
hinterlassen haben, und gibt einen neuen zurück. Er bekommt außerdem, was er zur Berechnung
brauchen kann:
| Argument | Was es ist |
|---|---|
transform | Der bisherige Versatz. |
overlayRect | Die Overlay-Box, um transform verschoben, in der Größe, die sie jetzt hat. |
activeRect | Das gezogene Element beim Start des Drags. |
containerRect | Der Container, in dem der Drag gestartet ist (die sortierbare Liste oder das Elternelement), dort, wo er jetzt ist: Er folgt dem Scrollen. |
windowRect | Das Fenster. |
origin | Der Zeiger beim Start des Drags. |
active, over | Der Drag und das Ziel darunter. |
Modifier laufen in jedem Frame: Halte sie schnell und frei von Seiteneffekten. Die Hilfslinien
oben werden aus dem delta des Drags im onDragMove eines Monitors gezeichnet, das der Versatz
nach allen Modifiern ist. Typen unter Modifier.
Die Reihenfolge
Modifier von mehreren Stellen laufen nacheinander, jeder auf dem Ergebnis des vorherigen:
- die
modifiersdes Providers; - die
modifiersdes Drag-Bereichs, in dem der Drag gestartet ist; - die eigenen
modifiersdes gezogenen Elements oder, wenn es keine hat, die seiner Liste oder seines Baums; restrictToAreades Drag-Bereichs;- die
axis-Sperre.
Innerhalb eines Arrays laufen sie der Reihe nach, setz also Einrasten und Magnete vor Grenzen: Eine
Grenze am Schluss hält die Box drinnen, was auch immer die anderen getan haben. Die Folie oben
führt [magnet, restrictToParent] aus; andersherum könnte der Magnet eine Box, die am Rand der
Folie gehalten wird, ein paar Pixel darüber hinausziehen.
Die modifiers eines Elements ersetzen die seiner Liste; sie kommen nicht hinzu. Die Grenzen
des Bereichs kommen nach dem Einrasten der Schritte 1–3, ein eingerastetes Element bleibt also
trotzdem drinnen, und die Achsensperre kommt ganz zum Schluss.
Begrenzte Listen behalten ihre Enden
Ein Ebenen-Panel: Zeilen bewegen sich nur hoch und runter und verlassen das Panel nie. Ziehe die oberste Zeile ganz nach unten:
Demo wird geladen…
<script setup lang="ts">
import { DnDProvider } from '@vue-dnd-kit/core';
import Layers from './Layers.vue';
</script>
<template>
<DnDProvider>
<Layers />
</DnDProvider>
</template>const { items } = makeSortableList(list, { items: layers, axis: 'y', modifiers: [restrictToParent] });
Eine Grenze hält das Overlay am Rand der Box, während der Zeiger weitergeht. Sobald der Zeiger das Overlay entlang der Achse der Liste verlassen hat, sortiert die Liste stattdessen nach dem Zeiger, also bleiben der erste und der letzte Platz erreichbar, wie auch immer du das Element hältst. Raster sortieren weiter nach dem Overlay: Am Rand gehalten, deckt es die Randzelle schon ab.
Regeln für einen Teil der Seite
Zwei Bereiche, zwei Regelsätze. Sticker in Layout rasten an dessen Raster ein und können es nicht verlassen; Sticker in Sketch gehen überallhin, auch in Layout. Ein Drag behält die Regeln des Bereichs, in dem er gestartet ist, und der Bereich, dessen Regeln gelten, leuchtet auf.
Demo wird geladen…
<script setup lang="ts">
import { ref } from 'vue';
import { DnDProvider, type Coordinates, type Key } from '@vue-dnd-kit/core';
import DragArea from './DragArea.vue';
const stickers = ref([
{ id: 'logo', text: 'Logo', color: '#42b883', area: 'sketch', x: 20, y: 24 },
{ id: 'photo', text: 'Photo', color: '#3b82f6', area: 'sketch', x: 110, y: 96 },
{ id: 'quote', text: 'Quote', color: '#ec4899', area: 'sketch', x: 36, y: 150 },
{ id: 'title', text: 'Title', color: '#f59e0b', area: 'layout', x: 24, y: 24 },
{ id: 'button', text: 'Button', color: '#a855f7', area: 'layout', x: 120, y: 144 },
]);
const place = (area: string, id: Key, at: Coordinates) => {
const sticker = stickers.value.find((item) => item.id === id);
if (!sticker) return;
sticker.area = area;
sticker.x = Math.round(at.x);
sticker.y = Math.round(at.y);
};
</script>
<template>
<DnDProvider>
<div class="studio">
<DragArea
id="sketch"
title="Sketch"
rules="no rules"
:stickers="stickers.filter((sticker) => sticker.area === 'sketch')"
@place="place"
/>
<DragArea
id="layout"
title="Layout"
rules="snapToGrid(24) · restrictToArea"
strict
:stickers="stickers.filter((sticker) => sticker.area === 'layout')"
@place="place"
/>
</div>
</DnDProvider>
</template>
<style scoped>
.studio {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
gap: 12px;
width: 100%;
max-width: 560px;
margin: 0 auto;
}
</style><script setup lang="ts">
const area = useTemplateRef<HTMLElement>('area');
const { isDragging } = makeDragArea(area, {
modifiers: () => (props.strict ? [snapToGrid(24)] : []),
restrictToArea: () => props.strict,
});
</script>
<template>
<div ref="area" class="area" :class="{ busy: isDragging }">
<Sticker v-for="sticker in stickers" :key="sticker.id" :sticker="sticker" />
</div>
</template>
makeDragArea legt Regeln für die Drags fest, die in seinem Element starten – einfache
ziehbare Elemente und sortierbare Elemente gleichermaßen, die dann keine eigenen Regeln brauchen.
Behalte einen DnDProvider für die ganze App und gib einem Board, einer Zeichenfläche oder einem
Feed einen eigenen Bereich.
| Option | Was sie tut |
|---|---|
axis | Sperrt die Drags auf eine Achse. Die eigene axis eines ziehbaren Elements oder die seiner Liste gewinnt. |
modifiers | Laufen nach denen des Providers und vor den eigenen des ziehbaren Elements. |
restrictToArea | true: Die Drags bleiben im Element des Bereichs. |
autoScroll | Auto-Scroll des Scroll-Containers des Bereichs (das Element oder sein nächster scrollbarer Vorfahr). false schaltet ihn dort ab. |
activation | Aktivierung je nach Zeigerart, etwa ein längeres Touch-Drücken in einem scrollenden Feed. Die eigene eines ziehbaren Elements gewinnt; die des Providers kommt zuletzt. |
disabled | Im Bereich startet kein Drag, auch nicht in den Bereichen darin. Seine ziehbaren Elemente melden aria-disabled. |
Jede Option nimmt einen Wert, ein Ref oder einen Getter, gelesen, wenn ein Drücken oder ein Drag
startet. Der Bereich gibt isDragging zurück (ein Drag, der hier gestartet ist, läuft, wie der
leuchtende Rahmen oben zeigt) und isAutoScrolling (Auto-Scroll bewegt seinen Container).
Vollständige Referenz: makeDragArea.
Wie Bereiche zusammenspielen
- Ein Drag folgt dem Bereich, in dem er gestartet ist, auch nachdem er ihn verlassen hat. Über
einen Bereich zu fahren ändert nichts, außer an seinem
autoScroll: Das gilt für jeden Drag, der seinen Container scrollt. - Verschachtelte Bereiche verschmelzen nicht: Der nächstgelegene gewinnt.
disabledist die Ausnahme und wird vererbt: Ein abgeschalteter Bereich schaltet auch die Bereiche darin ab. - Kollisionserkennung, Tastaturtasten und Ansagen bleiben providerweit.
DnDProvider um das Board? Provider sind unabhängig: Ein Drag wechselt nie von
einem zum anderen, die Elemente des Boards könnten es also nie verlassen. Verschachtle einen
Provider nur, wenn ein Teil der Seite eigene providerweite Einstellungen braucht und seine
Elemente darin bleiben. Siehe Der Provider.Dort lassen, wo es abgelegt wird
Die Zeitleiste, der Call, das Flussdiagramm, die Folie und die Bereiche oben lassen jedes Element
dort, wo es abgelegt wurde. Jedes Drag-Event trägt position: die linke obere Ecke der gezogenen
Box im Ziel, ab dessen Padding-Kante und mit dessen Scroll – das left und top, das ein absolut
positioniertes Element genau dorthin setzt. Es kommt nach den Modifiern, also landet ein
eingerasteter Knoten auf dem Raster.
makeDroppable(canvas, { id: 'canvas' });
useDnDMonitor({
onDragEnd({ active, over, position }) {
const node = nodes.value.find((item) => item.id === active.id);
if (!node || over?.id !== 'canvas' || !position) return;
node.x = Math.round(position.x);
node.y = Math.round(position.y);
},
});
Mehr zu freiem Ziehen und Drop-Zielen unter Drag and Drop.