What is HTML drag-and-drop?

HTML Træk-og-Slip: Skab Interaktive Webapps

23/02/2023

Rating: 4.99 (12700 votes)

I en verden, hvor brugervenlighed er altafgørende for digitale løsninger, står HTML træk-og-slip (drag-and-drop) som en hjørnesten i skabelsen af intuitive og interaktive webapplikationer. Denne funktionalitet, som mange kender fra desktopmiljøer, tillader brugere at interagere med webindhold på en mere naturlig og direkte måde – ved at flytte elementer rundt på skærmen med musen. Det handler ikke kun om at flytte filer; det kan være alt fra at omarrangere opgaver på en Kanban-tavle, tilføje varer til en indkøbskurv, eller sortere billeder i et galleri. Denne artikel vil dykke ned i, hvordan du kan implementere denne kraftfulde funktion i dine egne webprojekter, baseret på HTML's indbyggede muligheder.

Does HTML 5 support drag & drop?
The HTML 5 drag'n'drop API allows you to implement drag'n'drop on most desktop browsers and some mobile browsers. Unfortunately, you'll notice most mobile browsers don't support it, so no iPad (or Nexus) action for you! Chrome>=96 on Android>=7 and Safari on iOS/iPadOS>=15 are reported to support drag and drop natively!

HTML træk-og-slip-funktionaliteten bygger på DOM-hændelsesmodellen (Document Object Model) og arver træk-hændelser fra musehændelser. En typisk trækoperation begynder, når en bruger vælger et element, der kan trækkes. Den fortsætter, mens brugeren trækker elementet hen over potentielle drop-områder, og slutter, når brugeren slipper det trukne element. Undervejs udløses forskellige hændelsestyper, hvoraf nogle, som drag og dragover, kan udløses mange gange. Det er vigtigt at bemærke, at dragstart og dragend hændelser ikke udløses, når du trækker en fil ind i browseren fra operativsystemet – dette håndteres anderledes.

Indholdsfortegnelse

Grundlæggende Trin til Implementering af Træk-og-Slip

At tilføje træk-og-slip-funktionalitet til en applikation involverer en række veldefinerede trin. Ved at følge disse trin kan du opbygge robuste og brugervenlige interaktioner. Vi gennemgår hvert skridt i detaljer:

1. Identificer Trækbare Elementer

Det første skridt er at fortælle browseren, hvilke elementer på din webside der kan trækkes. Dette gøres simpelthen ved at tilføje draggable="true" attributten til HTML-elementet. Udover denne attribut skal du også lytte efter dragstart hændelsen på det trækbare element. Dette er det øjeblik, hvor trækoperationen officielt begynder, og det er her, du skal definere, hvilke data der skal overføres under trækket.

Forestil dig, at du har et simpelt afsnit, du gerne vil gøre trækbar:

<p id="mitElement" draggable="true">Dette element kan trækkes.</p>

For at håndtere dragstart hændelsen og forberede dataoverførslen, skal du tilføje en JavaScript event listener:

const element = document.getElementById("mitElement"); element.addEventListener("dragstart", (ev) => { // Tilføj elementets ID til dataoverførselsobjektet ev.dataTransfer.setData("text/plain", ev.target.id); });

I eksemplet ovenfor bruger vi ev.dataTransfer.setData("text/plain", ev.target.id);. ev.dataTransfer er et centralt objekt i træk-og-slip-API'en, og setData() metoden bruges til at gemme data, der skal overføres. Her gemmer vi elementets ID som almindelig tekst, hvilket er en almindelig og nyttig praksis, da det gør det nemt at finde elementet igen, når det slippes.

2. Definer Trækdata (Drag Data)

En trækoperation kan omfatte et vilkårligt antal dataelementer. Hvert dataelement er en streng af en bestemt type, typisk en MIME-type som text/html, text/plain eller text/uri-list. Det er her, fleksibiliteten i træk-og-slip virkelig skinner igennem; du kan overføre alt fra simpel tekst til komplekse JSON-objekter (serialiseret som strenge) eller endda referencer til filer.

Hver DragEvent har en dataTransfer ejendom, der indeholder hændelsens data. Denne ejendom, som er et DataTransfer objekt, har også metoder til at styre trækdata. Udover setData(), som vi allerede har set, findes der også getData() og clearData(). Det er god praksis at give så meget relevant data som muligt i forskellige formater, så dropzonen har flere muligheder for at håndtere droppet.

Her er et eksempel på, hvordan du kan definere forskellige typer trækdata i din dragstart handler:

function dragstartHandler(ev) { ev.dataTransfer.setData("text/plain", ev.target.innerText); // Tekstindhold ev.dataTransfer.setData("text/html", ev.target.outerHTML); // HTML-struktur ev.dataTransfer.setData("text/uri-list", ev.target.ownerDocument.location.href); // URL }

Ved at levere data i flere formater øges chancen for, at dropzonen kan håndtere dataen, uanset hvad den forventer. For eksempel kan en teksteditor bruge text/plain, mens en WYSIWYG-editor kan foretrække text/html.

3. Definer Trækbilledet (Drag Image)

Som standard leverer browseren et billede, der vises ved siden af markøren under en trækoperation. Dette er typisk en gennemsigtig kopi af det element, der trækkes. Men din applikation kan definere et brugerdefineret billede med setDragImage() metoden. Dette kan være nyttigt for at give bedre visuel feedback eller for at reducere den visuelle "støj", hvis det trukne element er meget stort eller komplekst.

For at definere et brugerdefineret trækbillede, skal du først oprette et Image objekt:

let img = new Image(); img.src = "sti/til/dit/billede.png"; // Husk at ændre til en faktisk billed-URL function dragstartHandler(ev) { ev.dataTransfer.setDragImage(img, 10, 10); // Billede, x-offset, y-offset }

setDragImage() tager tre argumenter: billedet, der skal bruges, og x- og y-koordinaterne for den relative position af markøren på billedet. Disse offsets er nyttige for at placere markøren præcist der, hvor brugeren forventer det – f.eks. i midten af et ikon eller i et bestemt hjørne af et større billede.

4. Definer Dropeffekt (Drop Effect)

dropEffect ejendommen bruges til at styre den feedback, brugeren får under en træk-og-slip-operation. Den påvirker typisk, hvilken markør browseren viser under trækket. Når brugeren f.eks. svæver over et drop-mål, kan browserens markør indikere den type handling, der vil finde sted (kopiering, flytning, eller oprettelse af et link). Dette er afgørende for en god brugeroplevelse, da det visuelt kommunikerer, hvad der er muligt.

Der kan defineres tre primære effekter:

  • copy: Indikerer, at de trukne data vil blive kopieret fra sin nuværende placering til drop-placeringen.
  • move: Indikerer, at de trukne data vil blive flyttet fra sin nuværende placering til drop-placeringen.
  • link: Indikerer, at en form for relation eller forbindelse vil blive oprettet mellem kilde- og drop-placeringerne.

Under trækoperationen kan træk-effekter ændres for at indikere, at visse effekter er tilladt på bestemte placeringer. Du kan sætte dropEffect i dragstart for at angive den ønskede effekt, men det er ofte i dragover hændelsen, at du justerer dropEffect baseret på den specifikke dropzone og de data, der trækkes.

Her er et eksempel på, hvordan du kan bruge denne ejendom i dragstart:

function dragstartHandler(ev) { ev.dataTransfer.dropEffect = "copy"; }

For at give et klarere overblik over dropEffect-værdierne, kan vi se på denne tabel:

Værdi af dropEffectBeskrivelseTypisk Markør
copyData kopieres fra kilden til destinationen. Kilden forbliver uændret.Plus-tegn (+) eller lignende
moveData flyttes fra kilden til destinationen. Kilden forventes at blive slettet.Standard pil eller bevægelsessymbol
linkDer oprettes en reference eller genvej til dataene.Kæde-symbol eller lignende
noneIngen handling er tilladt.Forbudt-symbol (cirkel med streg)

5. Definer en Dropzone

Som standard forhindrer browseren, at der sker noget, når man slipper noget på de fleste HTML-elementer. For at ændre denne adfærd, så et element bliver en dropzone eller kan modtage et drop, skal elementet lytte til både dragover og drop hændelserne. Dette er afgørende for, at browseren tillader et drop og for, at du kan håndtere de data, der droppes.

Den vigtigste del af dragover hændelsen er kaldet til preventDefault(). Hvis du ikke kalder preventDefault() i dragover hændelsen, vil elementet ikke fungere som en gyldig dropzone, og drop hændelsen vil aldrig blive udløst. Dette skyldes browserens standardadfærd, som forhindrer drops på de fleste elementer for at undgå uønskede handlinger (f.eks. at åbne en fil, der droppes på en webside).

Her er et eksempel på, hvordan du kan definere en dropzone:

<div id="dropZone" style="border: 2px dashed #ccc; padding: 20px; text-align: center;">Slip elementer her</div>

Og den tilhørende JavaScript-kode:

const target = document.getElementById("dropZone"); target.addEventListener("dragover", (ev) => { ev.preventDefault(); // Nødvendigt for at tillade et drop ev.dataTransfer.dropEffect = "move"; // Indikerer visuelt, at en flytning er mulig }); target.addEventListener("drop", (ev) => { ev.preventDefault(); // Forhindrer yderligere hændelsesbehandling (f.eks. filåbning) // Håndter de droppede data her, som beskrevet i næste trin });

Bemærk, at preventDefault() kaldes i begge handlere. I dragover er det for at tillade droppet, og i drop er det for at forhindre browserens standardadfærd efter et drop, som f.eks. at navigere til en fil, hvis den droppes. Du kan også justere dropEffect i dragover for at give dynamisk visuel feedback baseret på, hvilke data der trækkes, eller hvor de trækkes hen.

6. Håndter Drop-Effekten

Når et element er blevet droppet på en gyldig dropzone, udløses drop hændelsen. Handleren for denne hændelse er fri til at behandle trækdata på en applikationsspecifik måde. Typisk vil din applikation bruge getData() metoden til at hente de overførte dataelementer og derefter behandle dem i overensstemmelse hermed. Applikationens semantik kan også variere afhængigt af værdien af dropEffect og/eller tilstanden af modificeringstaster (f.eks. Alt, Shift, Ctrl).

getData() tager den samme type streng som argument, som blev brugt med setData(). Det er vigtigt at forsøge at hente data i de formater, din dropzone bedst kan håndtere, og falde tilbage til mere generiske formater, hvis de foretrukne ikke er tilgængelige.

Lad os se på et samlet eksempel, hvor et element trækkes og slippes ind i en dropzone:

<p id="kildeElement" draggable="true" style="border: 1px solid blue; padding: 10px; cursor: grab;">Træk mig!</p> <div id="dropTarget" style="border: 2px dashed green; padding: 30px; margin-top: 20px; text-align: center; min-height: 100px;">Dropzone her</div>

Og den fulde JavaScript-kode, der binder det hele sammen:

const source = document.getElementById("kildeElement"); const target = document.getElementById("dropTarget"); source.addEventListener("dragstart", (ev) => { ev.dataTransfer.setData("application/my-app", ev.target.id); // Gem elementets ID ev.dataTransfer.effectAllowed = "move"; // Angiver, at en flytning er tilladt source.style.opacity = '0.4'; // Gør elementet gennemsigtigt under træk }); target.addEventListener("dragover", (ev) => { ev.preventDefault(); // Tillader et drop ev.dataTransfer.dropEffect = "move"; // Indikerer, at flytning sker target.style.backgroundColor = '#e0ffe0'; // Visuel feedback for dragover }); target.addEventListener("dragleave", (ev) => { target.style.backgroundColor = 'transparent'; // Fjern visuel feedback når musen forlader }); target.addEventListener("drop", (ev) => { ev.preventDefault(); // Forhindrer browserens standardadfærd const data = ev.dataTransfer.getData("application/my-app"); // Hent det gemte ID const draggedElement = document.getElementById(data); if (draggedElement) { ev.target.appendChild(draggedElement); // Flyt elementet til dropzonen draggedElement.style.opacity = '1'; // Gendan opacitet target.style.backgroundColor = 'transparent'; // Fjern visuel feedback } }); source.addEventListener("dragend", (ev) => { // Denne hændelse udløses uanset om droppet lykkedes eller blev annulleret. // Du kan tjekke ev.dataTransfer.dropEffect for at se resultatet. if (ev.dataTransfer.dropEffect === "none") { source.style.opacity = '1'; // Gendan opacitet hvis droppet blev annulleret } });

I dette eksempel ser du, hvordan dataen (elementets ID) overføres fra kilden til målet, og hvordan målet bruger dette ID til at flytte det faktiske DOM-element. Derudover er der tilføjet simpel visuel feedback for at forbedre brugeroplevelsen under træk- og slip-operationen.

7. Træk Slut (Drag End)

Ved afslutningen af en trækoperation udløses dragend hændelsen på kildeelementet – det element, der var målet for dragstart. Denne hændelse udløses, uanset om trækket blev fuldført (f.eks. et vellykket drop) eller blev annulleret (f.eks. ved at slippe elementet uden for en gyldig dropzone eller ved at trykke på Esc-tasten).

dragend event handleren er et ideelt sted at udføre oprydningshandlinger eller at opdatere UI baseret på resultatet af trækoperationen. Du kan kontrollere værdien af ev.dataTransfer.dropEffect ejendommen for at afgøre, om trækoperationen lykkedes. Hvis dropEffect er none, betyder det, at trækket blev annulleret eller ikke resulterede i et gyldigt drop. Hvis det er copy, move eller link, indikerer det, at droppet lykkedes med den pågældende effekt.

element.addEventListener("dragend", (ev) => { // Gendan visuel tilstand, uanset om droppet lykkedes ev.target.style.opacity = '1'; if (ev.dataTransfer.dropEffect === "move") { // Hvis elementet blev flyttet, kan du f.eks. fjerne det fra den oprindelige placering, // hvis det ikke allerede er gjort af drop-handleren. console.log("Elementet blev flyttet."); } else if (ev.dataTransfer.dropEffect === "copy") { console.log("Elementet blev kopieret."); } else { console.log("Trækoperationen blev annulleret eller mislykkedes."); } });

Denne hændelse er essentiel for at sikre, at din applikations tilstand og brugerflade er konsistent efter en trækoperation, uanset dens udfald.

Vigtige Begivenheder i Træk-og-Slip

For at mestre HTML træk-og-slip er det afgørende at forstå de forskellige hændelser, der udløses under en trækoperation. Her er en oversigt over de vigtigste:

HændelseUdløses påBeskrivelse
dragstartTrækbar kildeNår brugeren begynder at trække et element. Her defineres trækdata.
dragTrækbar kildeUdløses kontinuerligt, mens et element trækkes. Kan bruges til visuel feedback.
dragenterDropzoneNår et trukket element kommer ind i en gyldig dropzone.
dragleaveDropzoneNår et trukket element forlader en dropzone.
dragoverDropzoneUdløses kontinuerligt, mens et element trækkes over en dropzone. Kræver preventDefault() for at tillade drop.
dropDropzoneNår et element slippes over en gyldig dropzone. Her håndteres de overførte data.
dragendTrækbar kildeNår trækoperationen er afsluttet (succesfuldt drop eller annulleret). Bruges til oprydning.

Ofte Stillede Spørgsmål (FAQ) om HTML Træk-og-Slip

Hvad er forskellen på dragover og drop hændelserne?

dragover hændelsen udløses gentagne gange, mens et element trækkes over en potentiel dropzone. Dens primære formål er at indikere, at et drop er muligt, og det er her, du skal kalde ev.preventDefault() for at tillade et drop. drop hændelsen udløses derimod kun én gang, når det trukne element faktisk slippes over en gyldig dropzone. Det er i drop hændelsen, at du skal hente og behandle de overførte data og udføre den ønskede handling, som f.eks. at flytte et element i DOM'en.

Hvorfor virker min dropzone ikke, selvom jeg har en drop event listener?

Den mest almindelige årsag til, at en dropzone ikke fungerer, er, at du ikke har kaldt ev.preventDefault() i din dragover event listener. Browserens standardadfærd er at forhindre drops på de fleste elementer, og ved at kalde preventDefault() overskriver du denne standardadfærd og signalerer, at elementet er en gyldig dropzone. Uden dette vil drop hændelsen aldrig blive udløst.

Kan jeg trække filer direkte fra mit operativsystem (f.eks. skrivebordet) ind i browseren ved hjælp af denne API?

Ja, det kan du, men der er en vigtig nuance: Når du trækker filer fra operativsystemet, udløses dragstart og dragend hændelserne ikke på din side, da kilden ikke er et HTML-element i DOM'en. Du kan dog stadig håndtere dragover og drop hændelserne på din dropzone. I drop hændelsen kan du få adgang til filerne via ev.dataTransfer.files ejendommen, som er en FileList, der indeholder File objekter. Dette er standardmåden at håndtere filuploads via træk-og-slip.

Hvad er dataTransfer-objektet, og hvorfor er det så vigtigt?

dataTransfer-objektet er kernen i dataudvekslingen under en træk-og-slip-operation. Det er en ejendom på DragEvent-objektet og fungerer som en midlertidig lagerplads for de data, der trækkes. Via setData() kan du gemme data fra kildeelementet, og via getData() kan du hente disse data i dropzonen. Det understøtter forskellige MIME-typer, hvilket gør det muligt at overføre forskellige former for information (tekst, HTML, URL'er osv.) og sikrer, at trækdata kan tilgås og fortolkes korrekt af modtageren.

Hvordan kan jeg tilpasse det billede, der vises, mens jeg trækker et element?

Du kan tilpasse træk-billedet ved at bruge ev.dataTransfer.setDragImage(imageElement, xOffset, yOffset) metoden i din dragstart event listener. imageElement kan være et eksisterende <img> element, et <canvas> element, eller et Image objekt, som du opretter i JavaScript. xOffset og yOffset bestemmer, hvor markøren skal placeres i forhold til billedets øverste venstre hjørne. Dette giver dig fuld kontrol over det visuelle feedback under trækoperationen.

Konklusion

HTML træk-og-slip-funktionaliteten er et utroligt kraftfuldt værktøj i arsenalet af enhver webudvikler. Ved at mestre de grundlæggende trin – fra at identificere trækbare elementer og definere trækdata til at opsætte dropzoner og håndtere drop-effekten – kan du skabe webapplikationer, der ikke kun er funktionelle, men også yderst intuitive og behagelige at bruge. Den detaljerede forståelse af dataTransfer-objektet og de forskellige træk-hændelser vil give dig fleksibiliteten til at implementere komplekse interaktioner, der forbedrer brugeroplevelsen markant.

Uanset om du bygger en filhåndtering, et opgaveboard eller en interaktiv editor, vil evnen til at implementere træk-og-slip løfte dine projekter til nye højder. Husk de vigtige punkter som preventDefault() i dragover og brugen af dataTransfer til at binde kilde og destination sammen. Med denne viden er du godt rustet til at begynde at bygge mere dynamiske og engagerende weboplevelser i dag.

Hvis du vil læse andre artikler, der ligner HTML Træk-og-Slip: Skab Interaktive Webapps, kan du besøge kategorien Teknologi.

Go up