La API de arrastrar y soltar de HTML5

En esta publicación, se explican los conceptos básicos de la función arrastrar y soltar.

Cómo crear contenido arrastrable

En la mayoría de los navegadores, las selecciones de texto, las imágenes y los vínculos pueden arrastrarse de forma predeterminada. Por ejemplo, si arrastras un vínculo en una página web, verás un pequeño cuadro con un título y la URL que puedes colocar en la barra de direcciones o en el escritorio para crear una atajo o navega hasta el vínculo. Para que otros tipos de contenido sean arrastrables, debes usar las APIs de arrastrar y soltar de HTML5.

Para que un objeto sea arrastrable, configura draggable=true en ese elemento. Casi se puede arrastrar cualquier elemento, como imágenes, archivos, vínculos, archivos el lenguaje de marcado en tu página.

En el siguiente ejemplo, se crea una interfaz para reorganizar las columnas que se han diseñado con la cuadrícula de CSS. El lenguaje de marcado básico de las columnas se ve de la siguiente manera: El atributo draggable de cada columna configurada como true:

<div class="container">
  <div draggable="true" class="box">A</div>
  <div draggable="true" class="box">B</div>
  <div draggable="true" class="box">C</div>
</div>

A continuación, se muestra el código CSS para los elementos del contenedor y el cuadro. El único CSS relacionado la función de arrastre es la cursor: move propiedad. El resto del código controla el diseño del contenedor y los elementos de caja.

.container {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
}

.box {
  border: 3px solid #666;
  background-color: #ddd;
  border-radius: .5em;
  padding: 10px;
  cursor: move;
}

En este punto, puedes arrastrar los elementos, pero no sucederá nada más. Para agregar debes usar la API de JavaScript.

Cómo escuchar eventos de arrastre

Para supervisar el proceso de arrastre, puedes escuchar cualquiera de los siguientes eventos:

Para controlar el flujo de arrastre, necesitas algún tipo de elemento fuente (en el que el arrastre la carga útil de datos (lo que se arrastra) y un objetivo (un área para la caída). El elemento fuente puede ser casi cualquier tipo de elemento. El el destino es la zona de la función de soltar o el conjunto de estas que acepta los datos que utiliza el usuario están tratando de caer. No todos los elementos pueden ser objetivos. Por ejemplo, tu objetivo no puede sea una imagen.

Cómo iniciar y finalizar una secuencia de arrastre

Después de definir los atributos draggable="true" en tu contenido, adjunta un Controlador de eventos dragstart para iniciar la secuencia de arrastre de cada columna.

Este código establece la opacidad de la columna en un 40% cuando el usuario comienza a arrastrarla y lo volverá al 100% cuando finalice el evento de arrastre.

function handleDragStart(e) {
  this.style.opacity = '0.4';
}

function handleDragEnd(e) {
  this.style.opacity = '1';
}

let items = document.querySelectorAll('.container .box');
items.forEach(function (item) {
  item.addEventListener('dragstart', handleDragStart);
  item.addEventListener('dragend', handleDragEnd);
});

El resultado se puede ver en la siguiente demostración de Glitch. Arrastrar un elemento y sus cambia la opacidad. Como el elemento de origen tiene el evento dragstart, establecer El porcentaje de this.style.opacity al 40% le indica al usuario que el elemento se se está moviendo la selección actual. Cuando sueltas el elemento, el elemento de origen vuelve al 100% de opacidad, incluso si aún no definiste el comportamiento de la acción de soltar.

Agrega señales visuales adicionales

Para ayudar al usuario a entender cómo interactuar con tu interfaz, usa el Controladores de eventos dragenter, dragover y dragleave. En este ejemplo, las columnas son objetivos para soltar, además de arrastrarse. Ayuda al usuario a entender esto haciendo que el borde sea discontinuo cuando sostienen un elemento arrastrado sobre un . Por ejemplo, en tu CSS, puedes crear una clase over para elementos que son destinos para soltar:

.box.over {
  border: 3px dotted #666;
}

Luego, en tu JavaScript, configura los controladores de eventos, agrega la clase over cuando la columna se arrastra y se la quita cuando sale el elemento arrastrado. En dragend, también nos aseguramos de quitar las clases al final de la arrastrar.

document.addEventListener('DOMContentLoaded', (event) => {

  function handleDragStart(e) {
    this.style.opacity = '0.4';
  }

  function handleDragEnd(e) {
    this.style.opacity = '1';

    items.forEach(function (item) {
      item.classList.remove('over');
    });
  }

  function handleDragOver(e) {
    e.preventDefault();
    return false;
  }

  function handleDragEnter(e) {
    this.classList.add('over');
  }

  function handleDragLeave(e) {
    this.classList.remove('over');
  }

  let items = document.querySelectorAll('.container .box');
  items.forEach(function(item) {
    item.addEventListener('dragstart', handleDragStart);
    item.addEventListener('dragover', handleDragOver);
    item.addEventListener('dragenter', handleDragEnter);
    item.addEventListener('dragleave', handleDragLeave);
    item.addEventListener('dragend', handleDragEnd);
    item.addEventListener('drop', handleDrop);
  });
});

Hay un par de puntos que vale la pena cubrir en este código:

  • La acción predeterminada del evento dragover es establecer la propiedad dataTransfer.dropEffect en "none" La propiedad dropEffect se analiza más adelante en esta página. Por ahora, solo debes saber que evita que se active el evento drop. Para anular esto nuevo, llama a e.preventDefault(). Otra práctica recomendada es devolver false en ese mismo controlador.

  • El controlador de eventos dragenter se usa para activar o desactivar la clase over en lugar de dragover Si usas dragover, el evento se activa repetidamente mientras el usuario. Contiene el elemento arrastrado sobre una columna, lo que hace que la clase de CSS active o desactive repetidamente. Esto hace que el navegador realice muchos trabajos de renderización innecesarios lo que puede afectar la experiencia del usuario. Recomendamos minimizar se vuelve a dibujar y, si necesitas usar dragover, considera restringir o anular el efecto de un objeto de escucha de eventos.

Completa la acción de soltar

Para procesar la acción de soltar, agrega un objeto de escucha de eventos para el evento drop. En drop del navegador, deberás evitar que se aplique el comportamiento predeterminado del navegador suele ser algún tipo de redireccionamiento molesto. Para ello, llama a e.stopPropagation().

function handleDrop(e) {
  e.stopPropagation(); // stops the browser from redirecting.
  return false;
}

Asegúrate de registrar el nuevo controlador junto con los otros controladores:

  let items = document.querySelectorAll('.container .box');
  items.forEach(function(item) {
    item.addEventListener('dragstart', handleDragStart);
    item.addEventListener('dragover', handleDragOver);
    item.addEventListener('dragenter', handleDragEnter);
    item.addEventListener('dragleave', handleDragLeave);
    item.addEventListener('dragend', handleDragEnd);
    item.addEventListener('drop', handleDrop);
  });

Si ejecutas el código en este punto, el elemento no cae en la nueva ubicación. Para haz que eso suceda, usa DataTransfer .

La propiedad dataTransfer contiene los datos enviados en una acción de arrastre. dataTransfer Se establece en el evento dragstart y se lee o controla en el evento de soltar. Llamando e.dataTransfer.setData(mimeType, dataPayload) te permite establecer el MIME del objeto. y la carga útil de datos.

En este ejemplo, vamos a permitir que los usuarios reorganicen el orden de las columnas. Para ello, primero debes almacenar el código HTML del elemento de origen cuando se arrastra comienza:

function handleDragStart(e) {
  this.style.opacity = '0.4';

  dragSrcEl = this;

  e.dataTransfer.effectAllowed = 'move';
  e.dataTransfer.setData('text/html', this.innerHTML);
}

En el evento drop, debes procesar el lanzamiento de columnas mediante la configuración del valor de HTML en el HTML de la columna de destino en la que colocaste los datos Esta incluye comprobar que el usuario no vuelva a la misma columna desde donde se arrastre.

function handleDrop(e) {
  e.stopPropagation();

  if (dragSrcEl !== this) {
    dragSrcEl.innerHTML = this.innerHTML;
    this.innerHTML = e.dataTransfer.getData('text/html');
  }

  return false;
}

Puedes ver el resultado en la siguiente demostración. Para que esto funcione, necesitarás una navegador para computadoras de escritorio. La API de arrastrar y soltar no es compatible con dispositivos móviles. Arrastrar y libera la columna A sobre la columna B y observa cómo cambian de lugar:

Más propiedades de arrastre

El objeto dataTransfer expone propiedades para brindar información visual al usuario durante el proceso de arrastre y controlar la forma en que cada destino para soltar responde a una tipo de datos determinado.

  • dataTransfer.effectAllowed restringe qué 'tipo de arrastre' que el usuario puede realizar en el elemento. Se usa en el modelo de procesamiento de arrastrar y soltar para inicializar dropEffect durante los eventos dragenter y dragover La propiedad puede tener la los siguientes valores: none, copy, copyLink, copyMove, link, linkMove, move, all y uninitialized.
  • dataTransfer.dropEffect controla los comentarios que recibe el usuario durante las fases dragenter y dragover eventos. Cuando el usuario mantiene el puntero sobre un elemento de destino, la ventana el cursor indica qué tipo de operación se llevará a cabo, como una copia o una mudanza. El efecto puede tener uno de los siguientes valores: none, copy, link, move
  • e.dataTransfer.setDragImage(imgElement, x, y) significa que, en vez de utilizar la "imagen fantasma" predeterminada del navegador, comentarios, tú puedes establecer un ícono de arrastrar.

Subir archivo

En este ejemplo simple, se usa una columna como fuente y destino de arrastre. Esta puede suceder en una IU que le pida al usuario que reorganice los elementos. En algunas situaciones, el destino de arrastre y el origen pueden ser de diferentes tipos de elementos, como en una interfaz en el que el usuario debe seleccionar una imagen como imagen principal de un producto arrastrando la imagen seleccionada a un objetivo.

La función de arrastrar y soltar se usa con frecuencia para permitir que los usuarios arrastren elementos de su escritorio a de una aplicación. La diferencia principal está en tu controlador drop. En lugar de usar dataTransfer.getData() para acceder a los archivos; sus datos se encuentran en Propiedad dataTransfer.files:

function handleDrop(e) {
  e.stopPropagation(); // Stops some browsers from redirecting.
  e.preventDefault();

  var files = e.dataTransfer.files;
  for (var i = 0, f; (f = files[i]); i++) {
    // Read the File objects in this FileList.
  }
}

Puedes encontrar más información sobre este tema en Función de arrastrar y soltar personalizada:

Más recursos