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
- Skapa en ny mapp för laborserien, t.ex.
lab-6. - Ladda ner
lab6.zip, packa upp och kolla att du harindex.htmlochstyle.css. - Skapa en
a.jsoch länka in den iindex.htmlmed<script type="module" src="a.js"></script>. - Öppna
index.htmlmed 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.
- Överst i scriptfilen, skapa en konstant
messagessom innehåller elementet med idmessages. - Skapa sedan en funktion
logEvent(event). - I funktionen, logga ut händelsetypen genom att konkatenera
event.typetilltextContentpå 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.
- Loopa igenom alla elementen med css-klassen
drag-item.- Gör elementen dragbara genom att sätta egenskapen
draggabletilltruepå varje sådant element. - Använd
addEventListenertre gånger för att lägga tilllogEventsom lyssnare på de tre händelsernadragstart,dragochdragend.
- Gör elementen dragbara genom att sätta egenskapen
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.
- Loopa igenom alla elementen med css-klassen
drop-zoneoch koppla eventlyssnare på samma sätt som ovan, men nu för händelsernadragenter,dragover,dragleaveochdrop. - Observera att på drop-zonerna skall du inte sätta
draggable = trueeftersom 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å
drophä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:
- 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. - Använd
e.preventDefault()för att förhindra standardbeteendet att “avvisa” släpp. - Koppla funktionen till
dragover-händelsen på alla drop-zonerna (du behöver inte ta bortlogEvent, 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!