API Drag-and-Drop
Mutarea elementelor folosind API-ul Drag-and-Drop
API-ul Drag-and-Drop permite mutarea diferitelor elemente cu mouse-ul într-o poziție specifică pe pagina web. Când mutăm elemente, avem o sursă de mutare - elementul pe care îl mutăm cu mouse-ul, și o țintă de mutare - zona țintă pe pagina web (un alt element) unde trebuie să mutăm sursa de mutare.
Pentru a defini un element pe pagina web care poate fi mutat (sursa de tragere), pentru acest element trebuie să definim atributul draggable cu valoarea true. Teoretic, orice element al paginii web poate fi un element care poate fi tras. De exemplu:
<div style="width:50px;height:50px; background-color: red;" draggable="true"></div>
Implicit, elementele nu sunt tratabile.
Ca țintă pentru tragere poate servi orice element al paginii web.
După ce un element este definit ca fiind mutabil, trebuie de asemenea să definim acțiunile care sunt executate atunci când elementul este mutat. În timpul operației de tragere, se generează o serie de evenimente diferite:
- dragstart: generat când începe tragerea elementului
- drag: generat constant pe măsură ce elementul este tras
- dragend: generat când tragerea elementului este completă
- dragenter: generat când elementul intră în limitele zonei țintă
- dragover: generat constant, de mai multe ori pe secundă, pe măsură ce elementul este tras deasupra zonei țintă
- dragleave: generat când elementul părăsește zona țintă
- drop: generat când elementul trageabil este eliberat pe zona țintă
Manipulatorii tuturor evenimentelor de mutare enumerate mai sus primesc ca parametru un obiect de tip DragEvent. Acest tip moștenește proprietățile de la MouseEvent și, respectiv, de la tipul Event.
Manipulatorul evenimentului dragstart este definit pentru elementul trageabil, iar manipulatorii celorlalte evenimente sunt definiți pentru zona pe care trebuie să mutăm elementul. De exemplu:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>FDC.COM</title>
<style>
#source { width:50px; height:50px; background-color: red; display: inline-block;}
#target {width: 200px; height: 150px; overflow: hidden; border: #ccc 1px dashed;}
div{margin:5px;}
</style>
</head>
<body>
<div id="source" draggable="true"></div>
<div id="target"></div>
<script>
const source = document.getElementById("source");
source.addEventListener("dragstart", () => console.log("Drag operation started"));
const target = document.getElementById("target");
target.addEventListener("dragover", (event) => {
event.preventDefault();
console.log("Dragover operation");
});
target.addEventListener("drop", () => console.log("Drag operation finished"));
</script>
</body>
</html>
În acest caz, elementul mutabil are identificatorul source, și pentru el se înregistrează manipulatorul evenimentului "dragstart". El va fi generat când prindem elementul cu indicatorul mouse-ului și începem să-l mutăm.
Zona pe care mutăm elementul reprezintă un alt element cu identificatorul target. Pentru demonstrație, pentru el înregistrăm manipulatorii evenimentelor "dragover" și "drop". Evenimentul "dragover" va fi generat când elementul item va fi mutat deasupra elementului target.
Pentru a preveni generarea evenimentului "drop" în timpul mutării, în manipulatorul acestui eveniment se apelează metoda event.preventDefault(). Când vom elibera elementul item pe elementul target, va fi generat evenimentul "drop".

În exemplul prezentat mai sus, elementul trasabil nu se mută efectiv încă nicăieri. Acest lucru se datorează faptului că trebuie să stabilim datele care sunt mutate și să le obținem la finalizarea mutării. De exemplu:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>FDC.COM</title>
<style>
#source { width:50px; height:50px; background-color: red; display: inline-block;}
#target {width: 200px; height: 150px; overflow: hidden; border: #ccc 1px dashed;}
div{margin:5px;}
</style>
</head>
<body>
<div id="source" draggable="true"></div>
<div id="target"></div>
<script>
let dragged = null; // datele mutate
// sursa mutării
const source = document.getElementById("source");
// în manipulator stabilim referința la elementul care se mută
source.addEventListener("dragstart", (e) => dragged = e.target);
// zona țintă a mutării
const target = document.getElementById("target");
// prevenim evenimentul drop
target.addEventListener("dragover", (e) => e.preventDefault());
// copiem elementul trasabil și îl plasăm pe zona țintă
target.addEventListener("drop", (e) => e.target.appendChild(dragged.cloneNode()));
</script>
</body>
</html>
Aici, la începutul tragerii, salvăm obiectul mutat în variabila dragged
source.addEventListener("dragstart", (e) => dragged = e.target);
La finalizarea tragerii, plasăm o copie a elementului source pe elementul target
target.addEventListener("drop", (e) => e.target.appendChild(dragged.cloneNode()));
Astfel, la tragerea pe zona target vor fi adăugate copii ale elementului source.


Ca alternativă, putem efectua mutarea completă a elementului trasabil:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>FDC.COM</title>
<style>
#source { width:50px; height:50px; background-color: red; display: inline-block;}
#target {width: 200px; height: 150px; overflow: hidden; border: #ccc 1px dashed;}
div{margin:5px;}
</style>
</head>
<body>
<div id="target"></div>
<div id="source" draggable="true"></div>
<script>
let dragged = null; // datele mutate
// sursa mutării
const source = document.getElementById("source");
// în manipulator stabilim referința la elementul care se mută
source.addEventListener("dragstart", (e) => dragged = e.target);
// zona țintă a mutării
const target = document.getElementById("target");
// prevenim evenimentul drop
target.addEventListener("dragover", (e) => e.preventDefault());
// mutăm complet elementul trasabil pe zona țintă
target.addEventListener("drop", (e) => {
dragged.parentNode.removeChild(dragged);
e.target.appendChild(dragged);
});
</script>
</body>
</html>
Aici, în manipulatorul "drop", mai întâi eliminăm elementul trasabil din containerul părinte (în acest caz, elementul body), apoi îl adăugăm pe zona țintă:
target.addEventListener("drop", (e) => {
dragged.parentNode.removeChild(dragged);
e.target.appendChild(dragged);
});

