En este tutorial, veremos cómo implementar el efecto de arrastrar y soltar en JavaScript vanilla. La traducción literal del inglés - "pull and drop" - refleja la esencia del efecto, esto es bien conocido por cualquier usuario que arrastre y suelte elementos de la interfaz.
Es posible que sea necesario arrastrar y soltar en diferentes situaciones, por ejemplo, en las siguientes:
Reposicionamiento visual simple de un elemento.
Ordene los elementos usando arrastrar y soltar. Un ejemplo es la clasificación de tarjetas de tareas en un rastreador de tareas.
Cambiar el contexto de un elemento. Ejemplo: transferir una tarea en un rastreador de tareas de una lista a otra.
Mover archivos locales a la ventana del navegador.
Echaremos un vistazo a arrastrar y soltar usando la ordenación como ejemplo. Para hacer esto, crearemos una lista de tareas interactiva.
API HTML de arrastrar y soltar
El estándar HTML5 tiene una API que permite arrastrar y soltar. Permite, mediante eventos especiales, controlar la captura de un elemento en la página por el mouse y su movimiento a una nueva posición. Echemos un vistazo más de cerca a esta API.
, . , , . , draggable
true
.
<div draggable="true">Draggable element</div>
, . MDN, .
drag
— , .
dragstart
— .
dragend
— , .
dragover
— , , .
drop
— , , .
. . , , dragover
drop
preventDefault
. — . .
API. , . , DataTransfer
, , . , DataTransfer
, , , , - . MDN.
, HTML Drag and Drop API.
. . — , ul
.
<section class="tasks">
<h1 class="tasks__title">To do list</h1>
<ul class="tasks__list">
<li class="tasks__item">learn HTML</li>
<li class="tasks__item">learn CSS</li>
<li class="tasks__item">learn JavaScript</li>
<li class="tasks__item">learn PHP</li>
<li class="tasks__item">stay alive</li>
</ul>
</section>
:
body {
font-family: "Tahoma", sans-serif;
font-size: 18px;
line-height: 25px;
color: #164a44;
background-color: #b2d9d0;
}
.tasks__title {
margin: 50px 0 20px 0;
text-align: center;
text-transform: uppercase;
}
.tasks__list {
margin: 0;
padding: 0;
list-style: none;
}
.tasks__item {
transition: background-color 0.5s;
margin-bottom: 10px;
padding: 5px;
text-align: center;
border: 2px dashed #b2d9d0;
border-radius: 10px;
cursor: move;
background-color: #dff2ef;
transition: background-color 0.5s;
}
.tasks__item:last-child {
margin-bottom: 0;
}
.selected {
opacity: 0.6;
}
, — move
. , move
, .
selected
,
drag & drop
1.
JavaScript. draggable
true
, . JavaScript.
const tasksListElement = document.querySelector(`.tasks__list`);
const taskElements = tasksListElement.querySelectorAll(`.tasks__item`);
//
for (const task of taskElements) {
task.draggable = true;
}
, . , .
2.
dragstart
dragend
. selected
, . .
tasksListElement.addEventListener(`dragstart`, (evt) => {
evt.target.classList.add(`selected`);
})
tasksListElement.addEventListener(`dragend`, (evt) => {
evt.target.classList.remove(`selected`);
});
3.
— . , dragover
. , , . :
.
.selected
,dragover
.
,
dragover
, — .
,
dragover
. , , .
, . , , .
.
:
tasksListElement.addEventListener(`dragover`, (evt) => {
//
evt.preventDefault();
//
const activeElement = tasksListElement.querySelector(`.selected`);
// ,
const currentElement = evt.target;
// , :
// 1. , ,
// 2.
const isMoveable = activeElement !== currentElement &&
currentElement.classList.contains(`tasks__item`);
// ,
if (!isMoveable) {
return;
}
// ,
const nextElement = (currentElement === activeElement.nextElementSibling) ?
currentElement.nextElementSibling :
currentElement;
// activeElement nextElement
tasksListElement.insertBefore(activeElement, nextElement);
});
— . , . — , . . . , , . , nextElement
.
4.
, dragover
. , . , , , . , .
getNextElement()
. , , . , .
, getBoundingClientRect()
. , . y
, height
,
, .
const getNextElement = (cursorPosition, currentElement) => {
//
const currentElementCoord = currentElement.getBoundingClientRect();
//
const currentElementCenter = currentElementCoord.y + currentElementCoord.height / 2;
// ,
// — DOM-
const nextElement = (cursorPosition < currentElementCenter) ?
currentElement :
currentElement.nextElementSibling;
return nextElement;
};
. , — , . , , DOM . , , .
, , - . , , . DOM dragover
. , DOM. , .
tasksListElement.addEventListener(`dragover`, (evt) => {
evt.preventDefault();
const activeElement = tasksListElement.querySelector(`.selected`);
const currentElement = evt.target;
const isMoveable = activeElement !== currentElement &&
currentElement.classList.contains(`tasks__item`);
if (!isMoveable) {
return;
}
// evt.clientY — ,
//
const nextElement = getNextElement(evt.clientY, currentElement);
// ,
if (
nextElement &&
activeElement === nextElement.previousElementSibling ||
activeElement === nextElement
) {
// , , DOM
return;
}
tasksListElement.insertBefore(activeElement, nextElement);
});
HTML Drag and Drop API MDN. API.
Native HTML5 Drag and Drop. API . .
How to make a Drag-and-Drop file uploader with vanilla JavaScript. , drag & drop.
Drag & drop . , HTML Drag and Drop API. , , - API .
10 Best Drag And Drop JavaScript Libraries. JavaScript-, drag & drop.
HTML Academy «React-» — JavaScript React.js . , . — . 95% . 27 .