Guía
EffDND añade la función de arrastrar y soltar a tu HTML con solo atributos. Sin llamadas a JavaScript ni configuración adicional más allá de una simple importación. Esta guía explica qué puedes hacer con él y cómo.
Primeros pasos
npm i effdndImporta una sola vez en tu aplicación:
import 'effdnd'; // la biblioteca
import 'effdnd/style.css'; // opcional: estilos predeterminadosEso es todo. Cualquier elemento marcado con los atributos que se indican a continuación se puede arrastrar inmediatamente, incluso los elementos añadidos posteriormente a la página.
Frameworks: funciona con cualquiera de ellos. No se necesita ningún componente contenedor.
Cómo funciona
EffDND se basa en una idea central, y todo lo demás en esta guía es una extensión de ella:
- Solo un
triggerinicia el arrastre. Ningún elemento se puede arrastrar por sí solo. Se agarra un punto de control marcado condata-dnd-triggery comienza el arrastre; sin él, nada se mueve. - El
itemes lo que se mueve. El trigger suele estar dentro del elemento, por lo que todo el elemento sigue el puntero, pero no tienen por qué ser el mismo nodo. - El
scopees el área de interacción. Elitemsolo puede moverse y soltarse dentro de suscope. Las zonas de suelta o los contenedores fuera de él simplemente se ignoran.
Este es el caso base: un trigger en un item dentro de un scope.
<div data-dnd-scope="board"> <!-- ámbito: el entorno aislado -->
<div data-dnd-item="a"> <!-- elemento: lo que se mueve -->
<span data-dnd-trigger>⠿</span> <!-- disparador: lo que agarras -->
Agárrame
</div>
</div>Cada una de las funciones que se describen a continuación —reordenar, transferir, desplazarse o los parámetros de activación que aparecen más abajo— solo refina o amplía este comportamiento básico.
Estilo al arrastrar. El elemento que ve moverse es un clon (una copia) del
item, insertado en el propio padre del elemento. Esto significa que los estilos en cascada y heredados, y las reglas escritas para los selectores padre (ul > li,.zone .card, …), siguen aplicándose al clon en movimiento; no es necesario aplicar estilos en línea a cada color. El elemento original permanece en su lugar en la lista y se atenúa mediante el estadopassive(consulte Estilo más abajo). Advertencia: elementos ancestros transformados. El clon tieneposition:fixed, por lo que está desvinculado del diseño. Pero si algún antecesor del elemento tienetransform,filter,perspective(owill-change:transform), el navegador tratafixedcomoabsolute: el clon se posiciona entonces en relación con ese antecesor y puede aparecer desplazado (y se desplazará con un contenedor transformado desplazable). Evite los antecesores transformados de los elementos arrastrados o anule los estilos visuales fijos mediantedata-dnd-statey los estilos en línea que aplique al elemento.
Atributos de un vistazo
| Atributo | Qué hace |
|---|---|
data-dnd-trigger | Marca el "controlador" desde el que el usuario arrastra |
data-dnd-item | Marca el elemento que se arrastra |
data-dnd-scope | Limita los destinos de arrastre y suelta a un solo contenedor |
data-dnd-reorder | Convierte un contenedor en una lista ordenable (x o y) |
data-dnd-target | Marca una zona de suelta |
data-dnd-transfer | Asigna una acción a una zona de suelta: append, prepend o remove |
data-dnd-scroll | Desplaza automáticamente el contenedor mientras se arrastra |
data-dnd-transition | Suaviza la animación de movimiento |
data-dnd-disabled | Deshabilita un activador |
data-dnd-state | Estado de ejecución (activo/pasivo) que se establece durante el arrastre — se usa para el estilo |
Solo se requieren tres de ellos para el caso más básico: un identificador (activador) en un elemento (item) dentro de un contenedor (scope). Todo lo demás es opcional y añade funcionalidad.
Parámetros de Trigger
Dado que el parámetro trigger es el punto de entrada, es el atributo que se ajusta con mayor frecuencia. Acepta una lista de parámetros separados por punto y coma:
<span data-dnd-trigger="dist:12;axis:y;scope:board;item:task-1">⠿</span>Requiere una distancia de arrastre (dist).
Evita arrastres accidentales al hacer clic: solo se arrastra después de que el puntero se mueva el número de píxeles especificado.
<span data-dnd-trigger="dist:12">⠿</span> <!-- solo se arrastra después de que el puntero se mueva 12px -->Bloquear a un eje (axis)
<span data-dnd-trigger="axis:x">⠿</span> <!-- horizontal solamente -->
<span data-dnd-trigger="axis:y">⠿</span> <!-- vertical solamente -->Acceda a un contenedor específico (scope).
Por defecto, EffDND encuentra el scope más cercano consultando el DOM. Si necesita uno específico, asígnele un nombre:
<span data-dnd-trigger="scope:board">⠿</span>Dirigirse a un elemento específico (item)
El activador puede especificar qué elemento específico de arriba se debe mover:
<span data-dnd-trigger="scope:board;item:task-1">⠿</span>Restringir los destinos de lanzamiento (target)
Permitir solo lanzar objetos en zonas cuyo data-dnd-target comience con el nombre especificado:
<span data-dnd-trigger="scope:board;target:drop">⠿</span>Muévase libremente por toda la página (scope:*)
El valor especial scope:* ignora por completo cualquier límite de scope:
<span data-dnd-trigger="scope:*">⠿</span>El elemento se puede arrastrar a cualquier parte de la página.
Desactivar un activador
<span data-dnd-trigger data-dnd-disabled>⠿</span>Elimina el atributo para volver a habilitarlo.
Escenarios típicos
Estas son las formas más comunes en que los componentes se combinan en interfaces reales.
Reordenar: una lista ordenable
Envuelve tus elementos en una lista con data-dnd-reorder="y", marca cada elemento y añade un identificador.
<ul data-dnd-scope="todo" data-dnd-reorder="y">
<li data-dnd-item="1"><span data-dnd-trigger>⠿</span>Buy milk</li>
<li data-dnd-item="2"><span data-dnd-trigger>⠿</span>Read a book</li>
</ul>yordena verticalmente,xordena horizontalmente.Solo se reordenan los elementos que son hijos directos de la lista.
Transferencia: mover elementos entre contenedores
Marque un contenedor como zona de destino y asígnele la acción de transferencia.
<div data-dnd-scope="sprint">
<div class="zone" data-dnd-target="backlog" data-dnd-transfer="append">Backlog</div>
<div class="zone" data-dnd-target="done" data-dnd-transfer="prepend">Done</div>
</div>append: el elemento se añade al final de la zona.prepend: el elemento se añade al inicio de la zona.remove: el elemento se elimina (ideal para una papelera).
Las zonas de destino deben estar dentro del mismo scope (o usar scope:*, ver más arriba).
Combinar: una lista ordenable con una papelera
<div data-dnd-scope="mailbox">
<ul data-dnd-reorder="y">
<li data-dnd-item="1"><span data-dnd-trigger>⠿</span>Invoice</li>
<li data-dnd-item="2"><span data-dnd-trigger>⠿</span>Newsletter</li>
</ul>
<button data-dnd-target="trash" data-dnd-transfer="remove">Delete</button>
</div>Aquí la lista se ordena sola y las filas se pueden descartar soltándolas en el botón.
Kanban: columnas y tarjetas
Dale al tablero data-dnd-reorder="x" para ordenar las columnas, y el área de la tarjeta de cada columna es una zona de reorden vertical y un receptor de transferencia.
<div data-dnd-scope="kanban" data-dnd-reorder="x"> <!-- ordena las columnas -->
<div class="col" data-dnd-item="col-1">
<div class="col-head"><span data-dnd-trigger>⠿</span>Backlog</div>
<div class="cards" data-dnd-reorder="y"
data-dnd-target="col-1" data-dnd-transfer="append"> <!-- clasifica y acepta tarjetas -->
<div class="card" data-dnd-item="task-1"><span data-dnd-trigger>⠿</span>Write spec</div>
</div>
</div>
<!-- más columnas ... -->
</div>Arrastra el encabezado de una columna para reordenar las columnas; arrastra una tarjeta para moverla entre columnas.
Ajuste de comportamientos comunes
Desplazamiento automático de un contenedor largo
Asigne data-dnd-scroll al elemento desplazable:
<div data-dnd-scroll="threshold:50;speed:12">umbral(valor predeterminado:30): indica la proximidad al borde a la que comienza el desplazamiento, en píxeles.velocidad(valor predeterminado:10): indica la velocidad de desplazamiento, en píxeles por fotograma.
Al arrastrar cerca del borde, el contenedor se desplaza, y la velocidad de desplazamiento aumenta a medida que te acercas al borde.
Suaviza la animación
<div data-dnd-transition="150ms ease">…</div>El valor predeterminado es 100 ms lineal.
Reacción a los arrastres desde JavaScript
Aún puedes hacerlo; EffDND simplemente lo hace opcional. Cada función a continuación devuelve una función para cancelar la suscripción:
import { onDrag, onDrop, onReorder, onTransfer, onDragStart, onDragEnd } from 'effdnd';
onReorder((event) => {
console.log('Item was reordered:', event.detail.keys.item);
});Eventos disponibles: effdragstart, effdrag, effdragend, effdragenter, effdragleave, effdrop, effreorder, efftransfer.
Cada evento proporciona un objeto detail en el que puede confiar:
event.detail.keys.item; // qué elemento
event.detail.keys.scope; // en qué ámbito
event.detail.keys.target; // sobre qué objetivo
event.detail.item;Ayudantes que pueden resultarle útiles
import { getItem, getScope, getTargets, getReorderContainer, reset } from 'effdnd';
getItem(trigger); // el `item` al que pertenece un elemento
getScope(trigger); // el ámbito al que pertenece un elemento
getTargets(trigger); // las zonas de lanzamiento disponibles para un activador
reset(item); // Devuelve el objeto a su posición original.Estilo con data-dnd-state
Durante un arrastre, EffDND etiqueta los elementos involucrados con el atributo data-dnd-state en tiempo de ejecución. Esto proporciona un gancho sencillo para aplicar estilos al arrastre activo, sin necesidad de JavaScript en línea. No hay data-dnd-state cuando no se está arrastrando nada.
Valores de estado
| Elemento | Estado | Significado |
|---|---|---|
data-dnd-item | active | El clon en movimiento: el elemento que sigue actualmente al puntero |
data-dnd-item | passive | El elemento original que permanece en su lugar, atenuado detrás del clon |
data-dnd-scope | active | El puntero está fuera del ámbito |
data-dnd-scope | passive | El puntero está dentro del ámbito: normal al arrastrar |
data-dnd-target | active | La zona de destino sobre la que se encuentra el cursor |
data-dnd-target | passive | Una zona de destino válida, lista para recibir un objeto |
El archivo index.css incluido ya contiene valores predeterminados adecuados basados en estos selectores, y se utilizan los mismos selectores para anularlos:
/* Valores predeterminados de index.css */
[data-dnd-item][data-dnd-state="passive"] { opacity: 0.2; }
[data-dnd-item][data-dnd-state="active"] { opacity: 0.75; z-index: 1000; }
/* Tu propio tema */
[data-dnd-item][data-dnd-state="passive"] { opacity: 0.08; }
[data-dnd-item][data-dnd-state="active"] {
opacity: 1;
box-shadow: 0 0 0 2px cornflowerblue;
border-radius: 8px;
}
[data-dnd-scope][data-dnd-state="active"] { outline: 2px dashed tomato; }
[data-dnd-target][data-dnd-state="active"] { background: rgba(100, 200, 255, 0.2); }Dado que los valores predeterminados se encuentran en index.css, cargarlos es opcional: si omite esa importación y escribe sus propias reglas [data-dnd-state="…"], EffDND permanece totalmente libre de dependencias y usted mantiene un control visual completo.
Consejo: El elemento original se atenúa mediante opacity, no se elimina, por lo que la lista conserva su diseño y
los elementos hermanos no se desplazan al arrastrar. Si desea que el elemento original desaparezca por completo, establezca
opacity: 0(ovisibility: hidden) para el estadopassive.
Minireferencia
Una versión condensada de cada atributo y sus parámetros.
| Atributo / parámetro | Valores | Predeterminado | Finalidad |
|---|---|---|---|
data-dnd-trigger | — | — | Marca el punto de inicio del arrastre |
… dist | número | — | Arrastra solo después de que el puntero se mueva esta cantidad de píxeles |
… axis | x / y | ambos | Bloquea el arrastre a un eje |
… scope | nombre / * | más cercano en el DOM | Usa un contenedor específico (o ignora los ámbitos) |
… item | nombre | más cercano en el DOM | Arrastra un elemento específico |
… target | nombre | todos | Solo permite soltar en objetivos que coincidan con un nombre |
data-dnd-disabled | — | — | Deshabilita un activador |
data-dnd-item | nombre único | — | Marca el elemento que se arrastra |
data-dnd-scope | nombre único | — | Limita los arrastres/soltados a un contenedor |
data-dnd-reorder | x / y | — | Convierte un contenedor en una lista ordenable |
data-dnd-target | nombre | — | Marca una zona de destino |
data-dnd-transfer | append / prepend / remove | — | Acción al soltar en una zona |
data-dnd-scroll | threshold;speed | 30;10 | Desplaza automáticamente el contenedor mientras se arrastra |
data-dnd-transition | duración y suavizado | 100ms lineal | Suaviza la animación de movimiento |
data-dnd-state | active / passive | — | Estado de arrastre en tiempo de ejecución, con estilo aplicado mediante CSS (ver Estilo) |