A continuación se describen los pasos que ocurren durante una operación de arrastrar y soltar.

Las operaciones de arrastre descritas en este documento utilizan la DataTransfer interfaz. Este documento no no utilizar el DataTransferItem interfaz ni el DataTransferItemList interfaz.

los draggable Atributo

En una página web, hay ciertos casos en los que se utiliza un comportamiento de arrastre predeterminado. Estos incluyen selecciones de texto, imágenes y enlaces. Cuando se arrastra una imagen o enlace, la URL de la imagen o enlace se establece como datos de arrastre y comienza un arrastre. Para otros elementos, deben ser parte de una selección para que ocurra un arrastre predeterminado. Para ver esto en efecto, seleccione un área de una página web y luego haga clic y mantenga presionado el mouse y arrastre la selección. Aparecerá una representación específica del sistema operativo de la selección y seguirá el puntero del mouse mientras se realiza el arrastre. Sin embargo, este comportamiento es solo el comportamiento de arrastre predeterminado, si ningún oyente ajusta los datos que se van a arrastrar.

En HTML, aparte del comportamiento predeterminado para imágenes, enlaces y selecciones, ningún otro elemento se puede arrastrar de forma predeterminada.

Para hacer que otros elementos HTML se puedan arrastrar, se deben hacer tres cosas:

  1. Selecciona el draggable= "true" en el elemento que desea hacer arrastrable.
  2. Agregue un oyente para el dragstart evento.
  3. Configure los datos de arrastre en el oyente anterior.

A continuación se muestra un ejemplo que permite arrastrar una sección de contenido.

<p draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'This text may be dragged')">
  This text <strong>may</strong> be dragged.
</p>

los draggable el atributo está establecido en "true", por lo que este elemento se puede arrastrar. Si este atributo se omitió o se estableció en "false", el elemento no se arrastraría, sino que se seleccionaría el texto.

los draggable El atributo se puede utilizar en cualquier elemento, incluidas imágenes y enlaces. Sin embargo, para estos dos últimos, el valor predeterminado es true, por lo que solo usaría el draggable atributo con un valor de false para deshabilitar el arrastre de estos elementos.

Nota: Cuando un elemento se puede arrastrar, el texto u otros elementos dentro de él ya no se pueden seleccionar de la manera normal haciendo clic y arrastrando con el mouse. En cambio, el usuario debe mantener presionada la tecla Alt para seleccionar texto con el mouse o usar el teclado.

Inicio de una operación de arrastre

En este ejemplo, se agrega un oyente para el dragstart evento usando el ondragstart atributo.

<p draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'This text may be dragged')">
  This text <strong>may</strong> be dragged.
</p>

Cuando un usuario comienza a arrastrar, el dragstart se dispara el evento.

En este ejemplo el dragstart El oyente se agrega al propio elemento arrastrable. sin embargo, podría escuchar a un antepasado superior a medida que surgen eventos de arrastre como lo hacen la mayoría de los demás eventos.

Dentro de dragstart evento, puede especificar el arrastrar datos, los imagen de retroalimentación, y el efectos de arrastre, todos los cuales se describen a continuación. Sin embargo, solo el arrastrar datos es requerido. (La imagen predeterminada y los efectos de arrastre son adecuados en la mayoría de situaciones).

Arrastrar datos

Todos drag events tener una propiedad llamada dataTransfer que contiene los datos de arrastredataTransfer es un DataTransfer objeto).

Cuando ocurre un arrastre, los datos deben estar asociados con el arrastre que identifica qué está siendo arrastrado. Por ejemplo, al arrastrar el texto seleccionado dentro de un cuadro de texto, los datos asociados con el arrastrar elemento de datos es el texto en sí. De manera similar, al arrastrar un enlace en una página web, el elemento de datos de arrastre es la URL del enlace.

los drag data contiene dos piezas de información, la escribe (o formato) de los datos, y la valor. El formato es una cadena de tipo (como text/plain para datos de texto) y el valor es una cadena de texto. Cuando comienza el arrastre, agrega datos proporcionando un tipo y los datos. Durante el arrastre, en un detector de eventos para el dragenter y dragover eventos, utiliza los tipos de datos de los datos que se arrastran para comprobar si se permite una caída. Por ejemplo, un destino para soltar que acepta enlaces buscaría el tipo text/uri-list. Durante un evento de caída, un oyente recuperaría los datos que se estaban arrastrando y los insertaría en la ubicación de colocación.

los drag data's types propiedad devuelve una lista de tipo MIME como DOMStrings, como text/plain o image/jpeg. También puede crear sus propios tipos. Los tipos más utilizados se enumeran en el artículo Tipos de arrastre recomendados.

Un arrastre puede incluir elementos de datos de varios tipos diferentes. Esto permite que los datos se proporcionen en tipos más específicos, a menudo tipos personalizados, y aún así proporcionar datos de respaldo para destinos de colocación que no admiten tipos más específicos. Suele darse el caso de que el tipo menos específico sean los datos de texto normales que utilizan el tipo text/plain. Estos datos serán una simple representación textual.

Para establecer un elemento de datos de arrastre dentro del dataTransfer, utilizar el setData() método. Toma dos argumentos: el tipo de datos y el valor de los datos. Por ejemplo:

event.dataTransfer.setData("text/plain", "Text to drag");

En este caso, el valor de los datos es “Texto para arrastrar” y tiene el formato text/plain.

Puede proporcionar datos en varios formatos. Para hacer esto, llame al setData() método varias veces con diferentes formatos. Debe llamarlo con formatos en orden del más específico al menos específico.

const dt = event.dataTransfer;
dt.setData("application/x.bookmark", bookmarkString);
dt.setData("text/uri-list", "https://www.mozilla.org");
dt.setData("text/plain", "https://www.mozilla.org");

Aquí, los datos se agregan en tres tipos diferentes. El primer tipo, application/x.bookmark, es un tipo personalizado. Otras aplicaciones no admitirán este tipo, pero puede usar un tipo personalizado para arrastrar entre áreas del mismo sitio o aplicación.

Al proporcionar datos en otros tipos también, también podemos admitir arrastres a otras aplicaciones en formas menos específicas. los application/x.bookmark type puede proporcionar datos con más detalles para su uso dentro de la aplicación, mientras que los otros tipos pueden incluir una única URL o versión de texto.

Tenga en cuenta que tanto el text/uri-list y text/plain contienen los mismos datos en este ejemplo. Esto a menudo será cierto, pero no tiene por qué ser así.

Si intenta agregar datos dos veces con el mismo formato, los datos nuevos reemplazarán a los datos antiguos, pero en la misma posición dentro de la lista de tipos que los datos antiguos.

Puede borrar los datos utilizando el clearData() método, que toma un argumento: el tipo de datos que se eliminarán.

event.dataTransfer.clearData("text/uri-list");

los type argumento a la clearData() el método es opcional. Si el type no se especifica, se eliminan los datos asociados con todos los tipos. Si el arrastre no contiene elementos de datos de arrastre, o si todos los elementos se borraron posteriormente, no se producirá ningún arrastre.

Configuración de la imagen de retroalimentación de arrastre

Cuando se produce un arrastre, se genera una imagen translúcida a partir del objetivo de arrastre (el elemento “dragstart“al que se dispara el evento) y sigue el puntero del usuario durante el arrastre. Esta imagen se crea automáticamente, por lo que no es necesario que la cree usted mismo. Sin embargo, puede usar setDragImage() para especificar una imagen de retroalimentación de arrastre personalizada.

event.dataTransfer.setDragImage(image, xOffset, yOffset);

Son necesarios tres argumentos. El primero es una referencia a una imagen. Esta referencia será típicamente a un <img> elemento, pero también puede ser a un <canvas> o cualquier otro elemento. La imagen de retroalimentación se generará a partir del aspecto que tenga la imagen en la pantalla, aunque en el caso de las imágenes, se dibujarán en su tamaño original. El segundo y tercer argumentos a la setDragImage() El método son compensaciones donde la imagen debería aparecer en relación con el puntero del mouse.

También es posible utilizar imágenes y lienzos que no están en un documento. Esta técnica es útil cuando se dibujan imágenes de arrastre personalizadas utilizando el elemento canvas, como en el siguiente ejemplo:

function dragWithCustomImage(event) {
  const canvas = document.createElement("canvas");
  canvas.width = canvas.height = 50;

  const ctx = canvas.getContext("2d");
  ctx.lineWidth = 4;
  ctx.moveTo(0, 0);
  ctx.lineTo(50, 50);
  ctx.moveTo(0, 50);
  ctx.lineTo(50, 0);
  ctx.stroke();

  const dt = event.dataTransfer;
  dt.setData('text/plain', 'Data to Drag');
  dt.setDragImage(canvas, 25, 25);
}

En este ejemplo, hacemos de un lienzo la imagen de arrastre. Como el lienzo es 50×50 píxeles, usamos compensaciones de la mitad de esto (25) para que la imagen aparezca centrada en el puntero del mouse.

Efectos de arrastre

Al arrastrar, hay varias operaciones que se pueden realizar. los copy La operación se utiliza para indicar que los datos que se arrastran se copiarán desde su ubicación actual a la ubicación de colocación. los move La operación se utiliza para indicar que los datos que se arrastran se moverán, y la link La operación se utiliza para indicar que se creará alguna forma de relación o conexión entre las ubicaciones de origen y de destino.

Puede especificar cuál de las tres operaciones está permitida para una fuente de arrastre configurando el effectAllowed propiedad dentro de una dragstart oyente de eventos.

event.dataTransfer.effectAllowed = "copy";

En este ejemplo, solo un Copiar esta permitido.

Puede combinar los valores de varias formas:

none
no se permite ninguna operación
copy
copy solamente
move
move solamente
link
link solamente
copyMove
copy o move solamente
copyLink
copy o link solamente
linkMove
link o move solamente
all
copy, move, o link
no inicializado
El valor predeterminado es all.

Tenga en cuenta que estos valores deben usarse exactamente como se enumeran anteriormente. Por ejemplo, configurar el effectAllowed propiedad a copyMove permite una operación de copiar o mover, pero evita que el usuario realice una operación de enlace. Si no cambia el effectAllowed propiedad, entonces se permite cualquier operación, al igual que con el ‘all‘ valor. Por lo tanto, no necesita ajustar esta propiedad a menos que desee excluir tipos específicos.

Durante una operación de arrastre, un oyente del dragenter o dragover los eventos pueden comprobar el effectAllowed propiedad para ver qué operaciones están permitidas. Una propiedad relacionada, dropEffect, debe establecerse dentro de uno de estos eventos para especificar qué operación única debe realizarse. Valores válidos para dropEffect están none, copy, move, o link. Los valores de combinación no se utilizan para esta propiedad.

Con el dragenter y dragover evento, el dropEffect La propiedad se inicializa al efecto que el usuario está solicitando. El usuario puede modificar el efecto deseado presionando las teclas modificadoras. Aunque las claves exactas utilizadas varían según la plataforma, normalmente el Cambio y Control las teclas se utilizarían para alternar entre copiar, mover y vincular. El puntero del mouse cambiará para indicar qué operación se desea. Por ejemplo, para un copy, el cursor puede aparecer con un signo más al lado.

Puede modificar el dropEffect propiedad durante el dragenter o dragover eventos, si, por ejemplo, un destino de colocación en particular solo admite ciertas operaciones. Puede modificar el dropEffect propiedad para anular el efecto de usuario y hacer cumplir una operación de caída específica para que se produzca. Tenga en cuenta que este efecto debe estar incluido en el effectAllowed propiedad. De lo contrario, se establecerá en un valor alternativo permitido.

event.dataTransfer.dropEffect = "copy";

En este ejemplo, copiar es el efecto que se realiza.

Puedes usar el valor none para indicar que no se permite dejar caer en esta ubicación, aunque se prefiere no cancelar el evento en este caso.

Dentro de drop y dragend eventos, puede consultar el dropEffect propiedad para determinar qué efecto se eligió en última instancia. Si el efecto elegido fuera “move“, los datos originales deben eliminarse del origen del arrastre dentro del dragend evento.

Especificación de destinos de caída

Un oyente de la dragenter y dragover Los eventos se utilizan para indicar destinos de colocación válidos, es decir, lugares donde se pueden soltar elementos arrastrados. La mayoría de las áreas de una página web o aplicación no lugares válidos para soltar datos. Por lo tanto, el manejo predeterminado de estos eventos es no permitir una caída.

Si desea permitir una caída, debe evitar el manejo predeterminado cancelando tanto el dragenter y dragover eventos. Puede hacer esto regresando false desde oyentes de eventos definidos por atributos, o llamando al evento preventDefault() método. Esto último puede ser más factible en una función definida en un script separado.

<div ondragover="return false">
<div ondragover="event.preventDefault()">

Llamando al preventDefault() método durante un dragenter y dragover El evento indicará que se permite una caída en esa ubicación. Sin embargo, normalmente deseará llamar al preventDefault() método solo en determinadas situaciones (por ejemplo, solo si se arrastra un enlace).

Para hacer esto, llame a una función que verifica una condición y solo cancela el evento cuando se cumple la condición. Si no se cumple la condición, no cancele el evento y no se producirá una caída allí si el usuario suelta el botón del mouse.

Es más común aceptar o rechazar una gota según el tipo de datos de arrastre en la transferencia de datos, por ejemplo, permitir imágenes, enlaces o ambos. Para hacer esto, puede verificar el types propiedad del evento dataTransfer (propiedad). los types La propiedad devuelve una matriz de los tipos de cadenas que se agregaron cuando comenzó el arrastre, en el orden del más significativo al menos significativo.

function doDragOver(event) {
  const isLink = event.dataTransfer.types.includes("text/uri-list");
  if (isLink) {
    event.preventDefault();
  }
}

En este ejemplo, usamos el includes método para comprobar si el tipo text/uri-list está presente en la lista de tipos. Si es así, cancelaremos el evento para que se permita una entrega. Si los datos de arrastre no contienen un enlace, el evento no se cancelará y no se podrá soltar en esa ubicación.

Es posible que también desee configurar el effectAllowed, dropEffect propiedad, o ambos al mismo tiempo, si desea ser más específico sobre el tipo de operación que se realizará. Naturalmente, cambiar cualquiera de las propiedades no tendrá ningún efecto si no cancela el evento también.

Dejar comentarios

Hay varias formas en las que puede indicarle al usuario que se permite una entrega en una ubicación determinada. El puntero del mouse se actualizará según sea necesario dependiendo del valor de la dropEffect propiedad.

Aunque la apariencia exacta depende de la plataforma del usuario, normalmente aparecerá un icono de signo más para un ‘copy‘por ejemplo, y aparecerá un icono de’ no se puede colocar aquí ‘cuando no se permita una gota. Esta retroalimentación del puntero del mouse es suficiente en muchos casos.

Sin embargo, también puede actualizar la interfaz de usuario con un punto de inserción o resaltar según sea necesario. Para un resaltado simple, puede usar el :-moz-drag-over Pseudoclase CSS en un destino de colocación.

.droparea:-moz-drag-over {
  outline: 1px solid black;
}

En este ejemplo, el elemento con la clase droparea recibirá un contorno negro de 1 píxel mientras sea un destino de caída válido, es decir, si el preventDefault() se llamó al método durante el dragenter evento.

Nota: Debes cancelar el dragenter evento para que se aplique esta pseudoclase, ya que este estado no se comprueba para el dragover evento.

Para efectos visuales más complejos, también puede realizar otras operaciones durante la dragenter evento. Por ejemplo, insertando un elemento en la ubicación donde ocurrirá la caída. Puede ser un marcador de inserción o un elemento que represente el elemento arrastrado en su nueva ubicación. Para hacer esto, puede crear un imagen o separador elemento e insértelo en el documento durante el dragenter evento.

los dragover El evento disparará al elemento al que apunta el mouse. Naturalmente, es posible que deba mover el marcador de inserción alrededor de un dragover evento también. Puedes usar el evento clientX y clientY propiedades como con otros eventos del mouse para determinar la ubicación del puntero del mouse.

Finalmente, el dragleave El evento disparará a un elemento cuando el arrastre abandone el elemento. Este es el momento en el que debe eliminar cualquier marcador de inserción o resaltado. No es necesario cancelar este evento. Cualquier resaltado u otros efectos visuales especificados mediante el :-moz-drag-over La pseudoclase se eliminará automáticamente. los dragleave El evento siempre se activará, incluso si se cancela el arrastre, por lo que siempre puede asegurarse de que se pueda realizar cualquier limpieza del punto de inserción durante este evento.

Realizar una gota

Cuando el usuario suelta el mouse, la operación de arrastrar y soltar termina.

Si se suelta el mouse sobre un elemento que es un destino de colocación válido, es decir, uno que canceló el último dragenter o dragover evento, entonces la caída será exitosa, y un drop El evento disparará al objetivo. De lo contrario, la operación de arrastre se cancela y no drop se dispara el evento.

Durante el drop evento, debe recuperar los datos que se eliminaron del evento e insertarlos en la ubicación de entrega. Puedes usar el dropEffect propiedad para determinar qué operación de arrastre se deseaba.

Al igual que con todos los eventos relacionados con el arrastre, el evento dataTransfer La propiedad contendrá los datos que se arrastran. los getData() El método puede usarse para recuperar los datos nuevamente.

function onDrop(event) {
  const data = event.dataTransfer.getData("text/plain");
  event.target.textContent = data;
  event.preventDefault();
}

los getData() El método toma un argumento, el tipo de datos a recuperar. Devolverá el valor de cadena que se estableció cuando setData() fue llamado al comienzo de la operación de arrastre. Se devolverá una cadena vacía si no existen datos de ese tipo. (Naturalmente, sin embargo, probablemente sabrá que el tipo correcto de datos estaba disponible, ya que se verificó previamente durante una dragover evento.)

En el ejemplo aquí, una vez que se han recuperado los datos, insertamos la cadena como el contenido textual del objetivo. Esto tiene el efecto de insertar el texto arrastrado donde se soltó, asumiendo que el destino de colocación es un área de texto como un p o div elemento.

En una página web, debe llamar al preventDefault() método del evento si ha aceptado la caída, de modo que el manejo predeterminado del navegador no se active también por los datos descartados. Por ejemplo, cuando se arrastra un enlace a una página web, Firefox abrirá el enlace. Al cancelar el evento, se evitará este comportamiento.

También puede recuperar otros tipos de datos. Si los datos son un enlace, debe tener el tipo text/uri-list. A continuación, puede insertar un enlace en el contenido.

function doDrop(event) {
  const lines = event.dataTransfer.getData("text/uri-list").split("n");
  lines.filter(line => !line.startsWith("#"))
    .forEach(line => {
      const link = document.createElement("a");
      link.href = line;
      link.textContent = line;
      event.target.appendChild(link);
    })
  event.preventDefault();
}

Este ejemplo inserta un enlace de los datos arrastrados. Como su nombre lo indica, el text/uri-list type en realidad puede contener una lista de URL, cada una en una línea separada. El código anterior utiliza split para dividir la cadena en líneas, luego itera sobre la lista de líneas e inserta cada una como un enlace en el documento. (Tenga en cuenta también que los enlaces que comienzan con un signo de número (#) se omiten, ya que son comentarios).

Para casos simples, puede utilizar el tipo especial URL solo para recuperar la primera URL válida de la lista. Por ejemplo:

const link = event.dataTransfer.getData("URL");

Esto elimina la necesidad de buscar comentarios o iterar a través de las líneas usted mismo. Sin embargo, está limitado solo a la primera URL de la lista.

los URL type es un tipo especial. Se usa solo como una abreviatura y no aparece dentro de la lista de tipos especificada en el types propiedad.

A veces, puede admitir algunos formatos diferentes y desea recuperar los datos más específicos admitidos. En el siguiente ejemplo, un destino de colocación admite tres formatos.

El siguiente ejemplo devuelve los datos asociados con el formato mejor admitido:

function doDrop(event) {
  const supportedTypes = ["application/x-moz-file", "text/uri-list", "text/plain"];
  const types = event.dataTransfer.types.filter(type => supportedTypes.includes(type));
  if (types.length) {
    const data = event.dataTransfer.getData(types[0]);
  }
  event.preventDefault();
}

Terminando un arrastre

Una vez que se completa el arrastre, dragend El evento se dispara en la fuente del arrastre (el mismo elemento que recibió el dragstart evento). Este evento se disparará si el arrastre fue exitoso.[1] o si fue cancelado. Sin embargo, puede utilizar el dropEffect propiedad para determinar qué operación de caída ocurrió.

Si el dropEffect la propiedad tiene el valor none durante un dragend, luego se canceló el arrastre. De lo contrario, el efecto especifica qué operación se realizó. La fuente puede utilizar esta información después de una move operación para eliminar el elemento arrastrado de la ubicación anterior. los mozUserCancelled la propiedad se establecerá en true si el usuario canceló el arrastre (presionando Escapar), y false si el arrastre se canceló por otras razones, como un destino de colocación no válido, o si tuvo éxito.

Una caída puede ocurrir dentro de la misma ventana o sobre otra aplicación. los dragend el evento siempre se disparará independientemente. Los eventos screenX y screenY Las propiedades se establecerán en las coordenadas de la pantalla donde ocurrió la caída.

Después de la dragend el evento ha terminado de propagarse, la operación de arrastrar y soltar está completa.

[1]: En Gecko, dragend no se envía si el nodo de origen se mueve o elimina durante el arrastre (por ejemplo, al soltar o dragover). Error 460801

Ver también