Webbteknik 2

Laboration 6A

Drag and Drop - Utforska händelser

I denna inledande övning ska vi inte bygga någon färdig funktion, utan bara studera hur webbläsaren beter sig när vi drar och släpper saker. Istället för att bara skriva till konsolen ska vi skriva ut händelserna direkt på sidan.

0 - Förberedelser

  1. Skapa en ny mapp för laborserien, t.ex. lab-6.
  2. Ladda ner lab6.zip, packa upp och kolla att du har index.html och style.css.
  3. Skapa en a.js och länka in den i index.html med <script type="module" src="a.js"></script>.
  4. Öppna index.html med Live Server. Du bör se fem rutor (A-E) och fyra tomma “drop zones”.

1 - En gemensam logg-funktion

För att göra koden mer läsbar ska vi börja använda namngivna funktioner som händelsehanterare (i stället för anonyma funktioner direkt i addEventListener).

Vi börjar med att skapa en funktion som skriver ut vilken typ av händelse som inträffade. Tanken är att vi skall använda samma funktion för att utforska alla händelser, och se när de avfyras i relation till varandra.

Vi kan döpa funktionen till logEvent. Den behöver ta emot event-objektet som argument, och tanken är att den skall logga ut händelsetypen genom att konkatenera event.type till textContent på messages-elementet.

  1. Överst i scriptfilen, skapa en konstant messages som innehåller elementet med id messages.
  2. Skapa sedan en funktion logEvent(event).
  3. I funktionen, logga ut händelsetypen genom att konkatenera event.type till textContent på messages-elementet.
Förslag på kod
const messages = document.getElementById('messages');

function logEvent(e) {
  messages.textContent += e.type + " - ";
}

2 - Koppla händelser på det som dras (drag item)

Det finns tre händelser som avfyras på själva elementet som dras: dragstart, drag och dragend. Nu skall vi koppla dessa händelser till vår generella logg-funktion.

  1. Loopa igenom alla elementen med css-klassen drag-item.
    • Gör elementen dragbara genom att sätta egenskapendraggable till true på varje sådant element.
    • Använd addEventListener tre gånger för att lägga till logEvent som lyssnare på de tre händelserna dragstart, drag och dragend.

Spara och experimentera med att dra elementen. Du bör nu se en ström av händelser i rutan längst ner på sidan!

Förslag på lösning
const draggables = document.querySelectorAll('.drag-item');

for (const draggable of draggables) {
  draggable.addEventListener('dragstart', logEvent);
  draggable.addEventListener('drag', logEvent);
  draggable.addEventListener('dragend', logEvent);
}

Tips: drag-händelsen avfyras väldigt ofta. Om det blir för rörigt kan du kommentera bort just den raden.

3 - Händelser på målet (drop zone)

När vi drar något över ett annat element, kan följande händelser avfyras på det elementet: dragenter, dragover, dragleave och drop.

  1. Loopa igenom alla elementen med css-klassen drop-zone och koppla eventlyssnare på samma sätt som ovan, men nu för händelserna dragenter, dragover, dragleave och drop.
  2. Observera att på drop-zonerna skall du inte sätta draggable = true eftersom de inte skall dras.
Förslag på lösning
const dropZones = document.querySelectorAll('.drop-zone');

for (const zone of dropZones) {
  zone.addEventListener('dragenter', logEvent);
  zone.addEventListener('dragover', logEvent);
  zone.addEventListener('dragleave', logEvent);
  zone.addEventListener('drop', logEvent);
}

Experimentera:

  • Prova nu att dra en ruta över de olika dropzonerna och observera vilka händelser som avfyras och i vilket ordning.
  • Prova även att släppa en ruta inuti en av drop-zonerna. Vad händer? Kan du på något sätt få drop händelsen att avfyras?

4 - Mysteriet med drop

Som standard tillåter inte webbläsare att man “släpper” saker på andra element. De flesta element (som div) är inte drop-zoner av naturen. Standardbeteendet är att “avvisa” släpp på element. Genom att hantera händelsen dragover kan vi förhindra det standardbeteendet.

I a.js:

  1. Skapa en separat funktion för dragover-händelserna, onDragOver(e), som vi kan använda för att tillåta släpp på drop-zonerna.
  2. Använd e.preventDefault() för att förhindra standardbeteendet att “avvisa” släpp.
  3. Koppla funktionen till dragover-händelsen på alla drop-zonerna (du behöver inte ta bort logEvent, det går bra att han flera händelsehanterare kopplade till samma event).
Förslag på lösning

Loopen nedan är samma som ni skrev ovan, bara en ny rad med den nya händelsehanteraren.

function onDragOver(event) {
  event.preventDefault(); // Förhindra standardbeteendet att "avvisa" släpp
}

const dropZones = document.querySelectorAll('.drop-zone');
for (const zone of dropZones) {
  zone.addEventListener('dragenter', logEvent);
  zone.addEventListener('dragover', logEvent);
  zone.addEventListener('dragover', onDragOver); // ny rad
  zone.addEventListener('dragleave', logEvent);
  zone.addEventListener('drop', logEvent);
}

Spara och testa igen. Nu när du släpper boxen i rutan, så bör du äntligen se din drop-händelse i listan!

Detta är en av de vanligaste fallgroparna i HTML5 Drag and Drop. Kom ihåg: Utan preventDefault på dragover sker ingen drop.

Nu när vi har en tydlig bild av händelseförloppet och har en fungerande drop-zone, är vi redo att börja implementera logiken i nästa laboration!