Documentación/Guías
Ejes, límites y cuadrículas
Bloquea los arrastres en un eje, mantenlos dentro de una caja, ajústalos a una cuadrícula o a guías propias — para un ítem, una lista o toda una parte de la página.
Esta página la ha traducido una IA y puede contener imprecisiones. Leer el original en inglés
Un arrastre puede sujetarse a un eje, mantenerse dentro de una caja, ajustarse a una cuadrícula o doblegarse a una regla tuya. Esas reglas son modificadores: ajustan el desplazamiento del arrastre en cada frame. Ponlos en un elemento arrastrable, en una lista o en una parte de la página, y el overlay, los destinos de drop y el drop los siguen.
Bloquear un eje
Los clips de una línea de tiempo se deslizan a lo largo de su pista. Quita el bloqueo y también podrán cambiar de pista.
Cargando la demo…
<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' solo mueve en horizontal, 'y' solo en vertical. makeDraggable, makeSortableList,
makeSortableTree, makeSortableItem y makeDragArea lo aceptan todos:
makeSortableList(listRef, { items: tracks, axis: 'y' });
- El bloqueo se ejecuta después de todos los modificadores, así que se mantiene hagan lo que hagan: un ajuste o un límite no puede sacar el ítem de su línea.
- La línea está en el contenido, no en la pantalla: se mueve con la lista (o el elemento padre) donde empezó el arrastre. Desplaza la página a mitad del arrastre y el ítem se queda en su fila.
- El
axispropio de un ítem gana al de su lista o su árbol, y el de un elemento arrastrable (o el de su lista) gana al de su área de arrastre. - Se lee cuando empieza un arrastre, así que un getter puede activarlo y desactivarlo, como arriba.
- Un árbol bloqueado en
'y'sigue anidando: la profundidad sale entonces de pasar sobre el centro de una fila.
axis a los modificadores restrictToVerticalAxis y restrictToHorizontalAxis. Hacen
lo mismo, pero como modificadores normales se ejecutan en medio de la cadena, y un modificador
posterior (una cuadrícula que ajusta los dos ejes) puede volver a sacar el ítem del eje.Modificadores
Un modificador ajusta el desplazamiento del arrastre en cada frame. Su resultado mueve el overlay
y es el punto donde se buscan los destinos, así que una lista ordena según la posición
bloqueada, limitada o ajustada, y la position del drop es donde acabó la caja.
| Modificador | Qué hace |
|---|---|
restrictToParent | Mantiene el overlay dentro del contenedor donde empezó el arrastre: la lista ordenable, o el elemento padre de un elemento arrastrable simple. |
restrictToElement(target) | Mantiene el overlay dentro de un elemento: una ref de plantilla, un getter o el propio elemento. |
restrictToWindowEdges | Mantiene el overlay dentro de la ventana. |
restrictToFirstScrollableAncestor | Mantiene el overlay dentro del primer ancestro desplazable del elemento arrastrado. |
snapToGrid(size) | Ajusta el overlay a una cuadrícula (más abajo). |
snapCenterToCursor | Centra el overlay bajo el puntero en lugar de mantener el desplazamiento del agarre. |
restrictToVerticalAxis | Solo se mueve en vertical. Prefiere axis: 'y'. |
restrictToHorizontalAxis | Solo se mueve en horizontal. Prefiere axis: 'x'. |
modifiers es una opción del provider, de las áreas de arrastre, de las listas y los árboles, y
de los elementos arrastrables y los ítems ordenables. Todas salvo la del provider aceptan además
una ref o un getter, que se leen cuando empieza el arrastre.
Mantenerlo dentro
Tu propia imagen en una videollamada se queda en la pantalla. Cambia el límite y arrástrala bien lejos:
Cargando la demo…
<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 []
});
restrictToParentla sujeta en la pantalla, su elemento padre. Para un ítem ordenable, el «padre» es su lista, esté donde esté la lista en el DOM.restrictToWindowEdgesla deja salir de la pantalla, pero no de la ventana. Si se suelta fuera de la pantalla, no está sobre ningún destino de drop, así que vuelve a su sitio.- Sin límite, va a cualquier parte.
Un límite mantiene dentro el overlay, con el tamaño que tenga: con overlayFit: 'slot', una
caja que crece sobre una lista de ítems más anchos se mantiene dentro con su nuevo tamaño.
Ajustar a una cuadrícula
Los nodos de un diagrama de flujo se ajustan a la cuadrícula del lienzo. Cambia el tamaño de la celda y el deslizamiento:
Cargando la demo…
<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) ajusta los dos ejes a celdas de 24 px. Un objeto permite ajustar más cosas:
| Opción | Significado |
|---|---|
x, y | El tamaño de la celda en píxeles, por eje. Omite uno para ajustar solo el otro: { y: 15 } ajusta un evento a cuartos de hora y lo deja moverse libremente entre los días. |
origin | 'container' (por defecto): la esquina superior izquierda del overlay cae en líneas de cuadrícula trazadas desde la esquina superior izquierda del contenedor — la lista ordenable, o el padre de un elemento arrastrable simple. 'delta': se redondea el propio desplazamiento, así que un ítem que empezó fuera de la cuadrícula se queda fuera de ella y se mueve por celdas enteras desde donde estaba. Elígelo para ítems colocados en cualquier sitio (un lienzo libre) que deben conservar su propia alineación. |
smooth | true o { duration, easing }: el overlay se desliza entre celdas (80 ms por defecto). Los destinos usan la posición ajustada de inmediato. |
Con origin: 'container', dibuja la cuadrícula desde la border box del contenedor: el lienzo de
arriba tiene su marco como box-shadow, no como border, así que sus líneas empiezan justo en el
borde.
Un modificador propio
Las cajas de una diapositiva saltan a los bordes y centros de las demás cuando se acercan, y unas guías rosas muestran las líneas sobre las que se colocan:
Cargando la demo…
<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];
Un modificador recibe transform, el desplazamiento desde el inicio del arrastre tal como lo
dejaron los modificadores anteriores, y devuelve uno nuevo. También recibe lo que pueda necesitar
para calcularlo:
| Argumento | Qué es |
|---|---|
transform | El desplazamiento hasta ahora. |
overlayRect | La caja del overlay movida por transform, con el tamaño que tiene ahora. |
activeRect | El elemento arrastrado cuando empezó el arrastre. |
containerRect | El contenedor donde empezó el arrastre (la lista ordenable, o el elemento padre), donde está ahora: sigue al scroll. |
windowRect | La ventana. |
origin | El puntero cuando empezó el arrastre. |
active, over | El arrastre y el destino que tiene debajo. |
Los modificadores se ejecutan en cada frame: mantenlos rápidos y sin efectos secundarios. Las
guías de arriba se dibujan a partir del delta del arrastre en el onDragMove de un monitor, que
es el desplazamiento después de todos los modificadores. Los tipos están en
Modificadores.
El orden
Los modificadores de varios sitios se ejecutan uno tras otro, cada uno sobre el resultado del anterior:
- los
modifiersdel provider; - los
modifiersdel área de arrastre donde empezó el arrastre; - los
modifierspropios del ítem arrastrado o, si no tiene, los de su lista o su árbol; - el
restrictToAreadel área de arrastre; - el bloqueo de
axis.
Dentro de un mismo array se ejecutan en orden, así que pon los ajustes y los imanes antes de los
límites: un límite al final mantiene la caja dentro hagan lo que hagan los demás. La diapositiva
de arriba ejecuta [magnet, restrictToParent]; al revés, el imán podría arrastrar unos píxeles
más allá del borde una caja sujeta en el borde de la diapositiva.
Los modifiers de un ítem sustituyen a los de su lista; no se suman. Los límites del área
vienen después de los ajustes de los pasos 1–3, así que un ítem ajustado sigue dentro, y el
bloqueo de eje va el último de todos.
Las listas limitadas conservan sus extremos
Un panel de capas: las filas solo se mueven arriba y abajo, y nunca salen del panel. Arrastra la fila de arriba hasta el final:
Cargando la demo…
<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] });
Un límite sujeta el overlay en el borde de la caja mientras el puntero sigue avanzando. En cuanto el puntero ha salido del overlay a lo largo del eje de la lista, la lista ordena según el puntero, así que el primer y el último puesto siguen a tu alcance sujetes como sujetes el ítem. Las cuadrículas siguen ordenando según el overlay: sujeto en el borde, ya cubre la celda del borde.
Reglas para una parte de la página
Dos áreas, dos conjuntos de reglas. Las pegatinas de Layout se ajustan a su cuadrícula y no pueden salir de ella; las de Sketch van a cualquier parte, también a Layout. Un arrastre conserva las reglas del área donde empezó, y se ilumina el área cuyas reglas están en vigor.
Cargando la demo…
<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 fija reglas para los arrastres que empiezan dentro de su elemento — tanto
elementos arrastrables simples como ítems ordenables, que entonces no necesitan reglas propias.
Mantén un único DnDProvider para toda la app, y dale a un tablero, un lienzo o un feed su propia
área.
| Opción | Qué hace |
|---|---|
axis | Bloquea los arrastres en un eje. Gana el axis propio de un elemento arrastrable, o el de su lista. |
modifiers | Se ejecutan después de los del provider y antes de los propios del elemento arrastrable. |
restrictToArea | true: los arrastres se quedan dentro del elemento del área. |
autoScroll | El desplazamiento automático del contenedor desplazable del área (el elemento, o su ancestro desplazable más cercano). false lo desactiva ahí. |
activation | La activación por tipo de puntero, como una pulsación táctil más larga en un feed que se desplaza. Gana la propia del elemento arrastrable; la del provider va la última. |
disabled | No empieza ningún arrastre en el área, ni en las áreas que contiene. Sus elementos arrastrables indican aria-disabled. |
Cada opción acepta un valor, una ref o un getter, que se leen cuando empieza una pulsación o un
arrastre. El área devuelve isDragging (hay en curso un arrastre que empezó aquí, como muestra el
marco iluminado de arriba) e isAutoScrolling (el desplazamiento automático está moviendo su
contenedor). Referencia completa: makeDragArea.
Cómo se combinan las áreas
- Un arrastre sigue al área donde empezó, incluso después de salir de ella. Pasar sobre un
área no cambia nada, salvo su
autoScroll: ese se aplica a cualquier arrastre que desplace su contenedor. - Las áreas anidadas no se fusionan: gana la más cercana.
disabledes la excepción, y se hereda: un área desactivada desactiva también las áreas que contiene. - La detección de colisiones, las teclas del teclado y los anuncios siguen siendo de todo el provider.
DnDProvider alrededor del tablero? Los providers son independientes: un
arrastre nunca pasa de uno a otro, así que los ítems del tablero nunca podrían salir de él. Anida
un provider solo cuando una parte de la página necesita sus propios ajustes a nivel de provider y
sus ítems se quedan dentro. Consulta El provider.Dejarlo donde se suelta
La línea de tiempo, la llamada, el diagrama de flujo, la diapositiva y las áreas de arriba
mantienen todos cada ítem donde se soltó. Cada evento de arrastre lleva position: la esquina
superior izquierda de la caja arrastrada dentro del destino, desde el borde de su padding y con su
scroll — el left y el top que colocan justo ahí un ítem con posición absoluta. Se calcula
después de los modificadores, así que un nodo ajustado aterriza en la cuadrícula.
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);
},
});
Más sobre el arrastre libre y los destinos de drop en Arrastrar y soltar.