|
3 weeks ago | |
---|---|---|
.. | ||
README.md | 3 weeks ago | |
assignment.md | 4 weeks ago |
README.md
Terrariumprojekt Del 3: DOM-manipulation och en Slutning
Sketchnote av Tomomi Imura
Förhandsquiz
Introduktion
Att manipulera DOM, eller "Document Object Model", är en central del av webbutveckling. Enligt MDN är "Document Object Model (DOM) den datarepresentation av objekten som utgör strukturen och innehållet i ett dokument på webben." Utmaningarna med att manipulera DOM har ofta varit anledningen till att använda JavaScript-ramverk istället för ren JavaScript för att hantera DOM, men vi kommer att klara oss själva!
Dessutom kommer denna lektion att introducera idén om en JavaScript-slutning, som du kan tänka på som en funktion innesluten av en annan funktion så att den inre funktionen har tillgång till den yttre funktionens scope.
JavaScript-slutningar är ett omfattande och komplext ämne. Denna lektion berör den mest grundläggande idén att i denna terrariums kod kommer du att hitta en slutning: en inre funktion och en yttre funktion konstruerade på ett sätt som tillåter den inre funktionen att få tillgång till den yttre funktionens scope. För mycket mer information om hur detta fungerar, besök den omfattande dokumentationen.
Vi kommer att använda en slutning för att manipulera DOM.
Tänk på DOM som ett träd som representerar alla sätt som ett webbdokument kan manipuleras. Olika API:er (Application Program Interfaces) har skrivits så att programmerare, med hjälp av sitt valda programmeringsspråk, kan komma åt DOM och redigera, ändra, omorganisera och på andra sätt hantera det.
En representation av DOM och HTML-markupen som refererar till det. Från Olfa Nasraoui
I denna lektion kommer vi att slutföra vårt interaktiva terrariumprojekt genom att skapa JavaScript som gör det möjligt för en användare att manipulera växterna på sidan.
Förkunskaper
Du bör ha HTML och CSS för ditt terrarium färdigbyggt. Vid slutet av denna lektion kommer du att kunna flytta växterna in och ut ur terrariet genom att dra dem.
Uppgift
I din terrarium-mapp, skapa en ny fil som heter script.js
. Importera den filen i <head>
-sektionen:
<script src="./script.js" defer></script>
Notera: använd
defer
när du importerar en extern JavaScript-fil i HTML-filen för att låta JavaScript exekveras först efter att HTML-filen har laddats helt. Du kan också använda attributetasync
, vilket tillåter att skriptet exekveras medan HTML-filen parsas, men i vårt fall är det viktigt att HTML-elementen är fullt tillgängliga för dragning innan vi låter drag-skriptet exekveras.
DOM-elementen
Det första du behöver göra är att skapa referenser till de element som du vill manipulera i DOM. I vårt fall är det de 14 växterna som för närvarande väntar i sidofälten.
Uppgift
dragElement(document.getElementById('plant1'));
dragElement(document.getElementById('plant2'));
dragElement(document.getElementById('plant3'));
dragElement(document.getElementById('plant4'));
dragElement(document.getElementById('plant5'));
dragElement(document.getElementById('plant6'));
dragElement(document.getElementById('plant7'));
dragElement(document.getElementById('plant8'));
dragElement(document.getElementById('plant9'));
dragElement(document.getElementById('plant10'));
dragElement(document.getElementById('plant11'));
dragElement(document.getElementById('plant12'));
dragElement(document.getElementById('plant13'));
dragElement(document.getElementById('plant14'));
Vad händer här? Du refererar till dokumentet och letar igenom dess DOM för att hitta ett element med ett specifikt Id. Kom ihåg att du i den första lektionen om HTML gav individuella Id:n till varje växtbild (id="plant1"
)? Nu kommer du att dra nytta av det arbetet. Efter att ha identifierat varje element skickar du det objektet till en funktion som heter dragElement
som du snart kommer att bygga. På så sätt blir elementet i HTML nu dragbart, eller kommer att bli det snart.
✅ Varför refererar vi till element med Id? Varför inte med deras CSS-klass? Du kan hänvisa till den tidigare lektionen om CSS för att svara på denna fråga.
Slutningen
Nu är du redo att skapa slutningen dragElement
, som är en yttre funktion som innesluter en inre funktion eller funktioner (i vårt fall kommer vi att ha tre).
Slutningar är användbara när en eller flera funktioner behöver tillgång till en yttre funktions scope. Här är ett exempel:
function displayCandy(){
let candy = ['jellybeans'];
function addCandy(candyType) {
candy.push(candyType)
}
addCandy('gumdrops');
}
displayCandy();
console.log(candy)
I detta exempel omger funktionen displayCandy
en funktion som lägger till en ny godistyp i en array som redan existerar i funktionen. Om du skulle köra denna kod skulle arrayen candy
vara odefinierad, eftersom den är en lokal variabel (lokal för slutningen).
✅ Hur kan du göra arrayen candy
tillgänglig? Försök att flytta den utanför slutningen. På så sätt blir arrayen global istället för att bara vara tillgänglig inom slutningens lokala scope.
Uppgift
Under elementdeklarationerna i script.js
, skapa en funktion:
function dragElement(terrariumElement) {
//set 4 positions for positioning on the screen
let pos1 = 0,
pos2 = 0,
pos3 = 0,
pos4 = 0;
terrariumElement.onpointerdown = pointerDrag;
}
dragElement
får sitt terrariumElement
-objekt från deklarationerna högst upp i skriptet. Sedan sätter du några lokala positioner till 0
för objektet som skickas in i funktionen. Dessa är de lokala variabler som kommer att manipuleras för varje element när du lägger till drag-och-släpp-funktionalitet inom slutningen för varje element. Terrariet kommer att fyllas med dessa dragna element, så applikationen behöver hålla reda på var de placeras.
Dessutom tilldelas terrariumElement
som skickas till denna funktion en pointerdown
-händelse, som är en del av webb-API:er designade för att hjälpa till med DOM-hantering. onpointerdown
triggas när en knapp trycks ner, eller i vårt fall, när ett dragbart element berörs. Denna händelsehanterare fungerar på både webb- och mobilwebbläsare, med några få undantag.
✅ Händelsehanteraren onclick
har mycket mer stöd över olika webbläsare; varför skulle du inte använda den här? Fundera på vilken exakt typ av skärminteraktion du försöker skapa här.
Pointerdrag-funktionen
terrariumElement
är redo att dras runt; när händelsen onpointerdown
triggas, anropas funktionen pointerDrag
. Lägg till den funktionen precis under denna rad: terrariumElement.onpointerdown = pointerDrag;
:
Uppgift
function pointerDrag(e) {
e.preventDefault();
console.log(e);
pos3 = e.clientX;
pos4 = e.clientY;
}
Flera saker händer. Först förhindrar du de standardhändelser som normalt inträffar vid pointerdown genom att använda e.preventDefault();
. På så sätt har du mer kontroll över gränssnittets beteende.
Återkom till denna rad när du har byggt klart skriptfilen och testa utan
e.preventDefault()
- vad händer?
För det andra, öppna index.html
i ett webbläsarfönster och inspektera gränssnittet. När du klickar på en växt kan du se hur händelsen 'e' fångas. Gräv i händelsen för att se hur mycket information som samlas in av en enda pointerdown-händelse!
Nästa steg är att notera hur de lokala variablerna pos3
och pos4
sätts till e.clientX. Du kan hitta värdena för e
i inspektionspanelen. Dessa värden fångar x- och y-koordinaterna för växten i det ögonblick du klickar på eller rör vid den. Du kommer att behöva finjusterad kontroll över växternas beteende när du klickar och drar dem, så du håller reda på deras koordinater.
✅ Börjar det bli tydligare varför hela denna app är byggd med en stor slutning? Om den inte var det, hur skulle du då kunna hålla scope för var och en av de 14 dragbara växterna?
Slutför den inledande funktionen genom att lägga till två fler pekarhändelsemanipulationer under pos4 = e.clientY
:
document.onpointermove = elementDrag;
document.onpointerup = stopElementDrag;
Nu anger du att du vill att växten ska dras med pekaren när du flyttar den, och att draggesten ska sluta när du avmarkerar växten. onpointermove
och onpointerup
är alla delar av samma API som onpointerdown
. Gränssnittet kommer nu att kasta fel eftersom du ännu inte har definierat funktionerna elementDrag
och stopElementDrag
, så bygg ut dem härnäst.
Funktionerna elementDrag och stopElementDrag
Du kommer att slutföra din slutning genom att lägga till två fler interna funktioner som hanterar vad som händer när du drar en växt och slutar dra den. Det beteende du vill ha är att du kan dra vilken växt som helst när som helst och placera den var som helst på skärmen. Detta gränssnitt är ganska flexibelt (det finns till exempel ingen dropzon) för att låta dig designa ditt terrarium precis som du vill genom att lägga till, ta bort och omplacera växter.
Uppgift
Lägg till funktionen elementDrag
precis efter den avslutande måsvingeparentesen för pointerDrag
:
function elementDrag(e) {
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
console.log(pos1, pos2, pos3, pos4);
terrariumElement.style.top = terrariumElement.offsetTop - pos2 + 'px';
terrariumElement.style.left = terrariumElement.offsetLeft - pos1 + 'px';
}
I denna funktion gör du många justeringar av de initiala positionerna 1-4 som du satte som lokala variabler i den yttre funktionen. Vad händer här?
När du drar omfördelar du pos1
genom att göra den lika med pos3
(som du tidigare satte som e.clientX
) minus det aktuella värdet för e.clientX
. Du gör en liknande operation för pos2
. Sedan återställer du pos3
och pos4
till de nya X- och Y-koordinaterna för elementet. Du kan se dessa förändringar i konsolen när du drar. Sedan manipulerar du växtens CSS-stil för att ställa in dess nya position baserat på de nya positionerna för pos1
och pos2
, och beräknar växtens topp- och vänsterkoordinater baserat på jämförelsen av dess offset med dessa nya positioner.
offsetTop
ochoffsetLeft
är CSS-egenskaper som ställer in ett elements position baserat på dess förälder; dess förälder kan vara vilket element som helst som inte är positionerat somstatic
.
Alla dessa omräkningar av positioner gör att du kan finjustera terrariets och växternas beteende.
Uppgift
Den sista uppgiften för att slutföra gränssnittet är att lägga till funktionen stopElementDrag
efter den avslutande måsvingeparentesen för elementDrag
:
function stopElementDrag() {
document.onpointerup = null;
document.onpointermove = null;
}
Denna lilla funktion återställer händelserna onpointerup
och onpointermove
så att du antingen kan starta om växtens rörelse genom att börja dra den igen, eller börja dra en ny växt.
✅ Vad händer om du inte sätter dessa händelser till null?
Nu har du slutfört ditt projekt!
🥇Grattis! Du har färdigställt ditt vackra terrarium.
🚀Utmaning
Lägg till en ny händelsehanterare i din slutning för att göra något mer med växterna; till exempel, dubbelklicka på en växt för att flytta den längst fram. Var kreativ!
Efterhandsquiz
Granskning & Självstudier
Även om det verkar trivialt att dra element runt på skärmen finns det många sätt att göra detta och många fallgropar, beroende på vilken effekt du vill uppnå. Faktum är att det finns ett helt drag-och-släpp-API som du kan prova. Vi använde det inte i denna modul eftersom effekten vi ville ha var något annorlunda, men prova detta API på ditt eget projekt och se vad du kan åstadkomma.
Hitta mer information om pekarhändelser i W3C-dokumentationen och på MDN webbdokumentation.
Kontrollera alltid webbläsarkapabiliteter med CanIUse.com.
Uppgift
Ansvarsfriskrivning:
Detta dokument har översatts med hjälp av AI-översättningstjänsten Co-op Translator. Även om vi strävar efter noggrannhet, vänligen notera att automatiska översättningar kan innehålla fel eller felaktigheter. Det ursprungliga dokumentet på dess originalspråk bör betraktas som den auktoritativa källan. För kritisk information rekommenderas professionell mänsklig översättning. Vi ansvarar inte för eventuella missförstånd eller feltolkningar som uppstår vid användning av denna översättning.