Slider i javascript
Hej hur skapar man slider för sidor?
Jag har 30 pages, en button som är previous å den andra som är next, Jag vill att varje gång jag klickar på knappen den ska visa svara antingen bakåt som är previous eller framåt som är next,
<div class="book">
<div class="book-pages">
<div class="pages">
<div class="page1">
<img src="page1.jpg">
</div>
</div>
<div class="pages">
<div class="page2">
<img src="page2.jpg">
</div>
</div>
</div>
<button id="previous">Previous</button>
<button id="next">Next</button>
</div>
De flesta element på en HTML-sida kan hantera händelser som berör just det elementet. Det kan t ex vara att ett element visas på skärmen eller att användaren klickar en knapp. Man säger att elementet "fångar" händelsen och gör något med den. "Något" i det här fallet är en javascript-kod.. Koden associeras med händelser med attributet on... där olika händelser har olika attribut. När man klickar på en knapp så hanteras det med attributet onclick. Attributet associeras med javascriptkod som
<button .... onclick="någon javascriptkod". />
Javaskriptkoden kan göra något direkt men det är nog vanligare att det är ett anrop till en javaskriptfunktion som definieras någon annan stans. I ditt fall så ska du ha två funktioner som bläddrar till nästa bild respektive till föregående bild.
Du kan läsa mer om events på följande länk https://www.w3schools.com/js/js_events.asp
Titta också på exemplet som borde leda dig i rätt riktning. Återkom om du har mer frågor.
Men det fungerar inte !
Prova med att lägga till onclick='goToPrevious' resp onclick='goToNext' på button i stället och ta bort addEventListener. Det kan ha att göra med att sidan inte är laddad när din js-kod laddas o körs och då finns inte dina element i DOM-trädet.
Jag kan också tipsa om att köra debuggern. Jag kör Firefox och där högerklickar man på ett element och väljer "Inspektera" så kan du se om du får något fel och du kan vandra runt i DOM-trädet och se vilka värden resp attribut har.
Här har du lite kod som gör något liknande som du försöker uppnå. Den fungerar så det borde din göra också. Kontrollera att dina metoder gör vad de ska med debugger eller spårutskrifter
Visa spoiler
Skriv ditt dolda innehåll här
<div class="book">
<div class="book-pages">
<div id='kalle' class="pages">
<div class="page1">
Kalle
</div>
</div>
<div id='pelle' class="pages" style="display: none">
<div class="page2">
Pelle
</div>
</div>
</div>
<button id="previous">Previous</button>
<button id="next">Next</button>
</div>
<script>
var prevBtn = document.getElementById('previous');
var nextBtn = document.getElementById('next');
prevBtn.addEventListener('click',goToPrev);
nextBtn.addEventListener('click',goToNext);
function goToPrev() {
document.getElementById('kalle').style.display = 'block';
document.getElementById('pelle').style.display = 'none';
}
function goToNext() {
document.getElementById('pelle').style.display = 'block';
document.getElementById('kalle').style.display = 'none';
}
</script>
varför har du : none display i klassen pelle???
tänk att jag har 32 sådana sidor som klassen pages!
för att lägga alla id i document blir det för långt, är det if eller for loop som spelar roll där?
Div pelle och kalle upptar samma plats på sidan, ungefär som jag tänker mig att bilder i ett bildspel gör så initialt visas Kalle och Pelle döljs. Knapparna används sen för att omväxlande visa de två divarna.
I ditt fall kan du t ex sätta samma namn (name=...) och sen använda getElementsByName som returnerar en vektor som du kan iterera framåt och bakåt med hjälp av ett index du kommer ihåg. Alternativt skapar du en vektor med alla bilder och skapar nya img-taggar när du bläddrar.
Det finns andra sätt men det här är det enklaste HTML/JS jag kan komma på.
Jag had lagt till id och JQuery kod. Initialt gömmer vi alla sidor med style="display: none;"
<div class="book">
<div class="book-pages">
<div class="pages page" id="page1" style="display: none;">
<div class="page-content">
<img src="page1.jpg">
</div>
</div>
<div class="pages page" id="page2" style="display: none;">
<div class="page-content">
<img src="page2.jpg">
</div>
</div>
<!-- Flera sidor .... -->
</div>
<button id="previous">Previous</button>
<button id="next">Next</button>
</div>
JQUERY
$(document).ready(function() {
var currentPage = 1;
var numberOfPages = $('.page').length;
// Function to update the page view
function updateView() {
$('.page').hide(); // hide all pages
$('#page' + currentPage).show(); // show current page
}
// Show the first page initially
updateView();
// Bind click event to the next button
$('#next').click(function() {
if(currentPage < numberOfPages) {
currentPage++; // increment current page number
updateView(); // update the view
}
});
// Bind click event to the previous button
$('#previous').click(function() {
if(currentPage > 1) {
currentPage--; // decrement current page number
updateView(); // update the view
}
});
});
typ... har inte testkört det själv ;)
<div class="book">
<div class="book-pages">
<div class="pages">
<div class="page1">
<img src="page1.jpg">
</div>
</div>
<div class="pages">
<div class="page2">
<img src="page2.jpg">
</div>
</div>
<!-- Fortsätt lägg till div-element för varje sida -->
</div>
<button id="previous">Previous</button>
<button id="next">Next</button>
</div>
.book-pages {
display: flex;
overflow-x: scroll;
scroll-snap-type: x mandatory;
}
.pages {
scroll-snap-align: start;
}
.page1,
.page2 {
width: 100%;
}
/* Lägg till fler sidor med motsvarande klasser */
button {
margin-top: 10px;
}
$(document).ready(function() {
var currentPage = 1;
var totalPages = $('.pages').length;
// Hantera klick på Previous-knappen
$('#previous').click(function() {
if (currentPage > 1) {
currentPage--;
$('.book-pages').animate({scrollLeft: $('.book-pages').scrollLeft() - $('.book-pages').width()}, 500);
}
});
// Hantera klick på Next-knappen
$('#next').click(function() {
if (currentPage < totalPages) {
currentPage++;
$('.book-pages').animate({scrollLeft: $('.book-pages').scrollLeft() + $('.book-pages').width()}, 500);
}
});
});
CurtJ skrev:Prova med att lägga till onclick='goToPrevious' resp onclick='goToNext' på button i stället och ta bort addEventListener. Det kan ha att göra med att sidan inte är laddad när din js-kod laddas o körs och då finns inte dina element i DOM-trädet.
Jag och en del andra JavaScript utvecklare jag jobbat med över åren inom E-handelssektorn brukar alltid ha som bäst praxis att "wrappa" all sin JS kod inuti en addEventListener för DOMContentLoaded eventet, alternativt kontrollera readystate om complete / window onload för att säkerställa att det man vill arbeta med finns redo.
- Läs mer om document.readyState här: https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
- Läs mer om window.onload här: https://stackoverflow.com/questions/588040/window-onload-vs-document-onload
- Alternativt om själva window load eventet (samma sak som ovan, bara två olika sätt att göra det på): https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
- Och här har ni om DOMContentLoaded eventet: https://developer.mozilla.org/en-US/docs/Web/API/Document/DOMContentLoaded_event
Always verify & doublecheck:
Det kan dock hända att saker sker även om man wrappar sin JS kod inuti något av ovan alternativ, så därför som extra precaution rekommenderar många som bäst praxis att Alltid kontrollera existens av element ditt script behöver för att köras innan man antar att de finns tillgängliga. För så är inte alltid fallet.
Detta gäller för övrigt inte bara JavaScript, utan är även relevant för andra kodspråk som PHP m.fl.
Ovan praktik kan liknas vid "JS Feature detection":
Feature detection likt biblioteket Modernizr från Paul Irish och hans vänner handlar om liknande metodik som släpptes för att hjälpa utvecklare kontrollera existens av den senaste cutting-edge JS funktionalitet som precis släppts och som ännu ej hunnit bli helt xbrowser/enhets-kompatibelt.
Kontrollera webbläsarstöd med hjälp av CanIUse.com:
För övrigt om ni inte redan känner till det så kan jag varmt rekommendera er kolla upp CSS-attribut, JS funktionalitet, måttenheter, m.m. via CanIUse.com för att se webbläsarkompatibilitet och stöd i dagens webbläsare/enheter just nu.
Ta aldrig något för givet i JavaScript
Ta aldrig något för givet i JavaScript. Har lärt mig det den hårda vägen. Oavsett om koden är wrappad i någon eventlyssnare för att se om DOM laddats eller samtliga Window element (bilder, script, taggar, osv.). Det finns flera olika bra metoder för att åstadkomma detta.
Exempelvis följande Vanilla JS kod som kontrollerar om ett HTML-element existerar och kan användas eller ej:var element = document.getElementById("elementID"); // (Notera document.querySelector och .querySelectorAll brukar ta mer prestanda än de klassiska document.getElementsByTagName och .getElementById)
if (typeof(element) != 'undefined' && element != null) { console.log("element exists"); }
Skapa de förutsättningar din kod behöver för att köras felfritt och stabilt, för det är inte alltid du kan lita på JavaScript att göra det åt dig.
Gällande "on-JS Trigger" HTML-Attribut:
Att använda HTML-attribut för on JS triggers brukar inte längre rekommenderas som bra praxis sen en tid tillbaka. Det kluddar upp HTML-koden och brukar försvåra underhåll. Bäst praxis brukar istället vara att hålla HTML5 för sig självt, CSS för sig självt (externt dokument, med vissa undantag) och Vanilla JS för sig självt i externt script dokument. Med vissa specifika undantagsfall såklart där on-page script-block kan vara alternativ. Beroende på när man behöver sin kod att köras, osv. Kan ofta ha med prestanda att göra då icke-asynkron JS kod räknas precis som CSS-kod, som render-blockerande, vilket innebär att det kan fördröja inladdning av hemsida medan webbläsaren bearbetar koden.
Event Delegation som alternativ till element-specifik addEventListener-fästning:
Ett alternativ för att applicera addEventListener för click snarare än att koppla på 1 eventlyssnare PER element du vill lyssna av klick på, är att fästa din click eventlyssnare på document
och sen inuti funktionen för eventlyssnaren "känna av" vilket element som klickades, genom att använda input parameter för funktionen för event
och använda en if-sats i kombination med event.target.id
eller event.target.classList.contains("klassnamn")
eller liknande för att se så rätt element faktiskt klickades.
Ett tips här kan vara att inuti din eventlyssnare console.log("event:", event);
för att printa innehållet av event-objektet vilket underlättar arbete när man ser vad man faktiskt har att arbeta med när ett event triggats :)
Varje eventlyssnare som fästs brukar belasta prestanda. Click eventlistenern funkar på document i.o.m. event bubbling som sker naturligt i JavaScript, vilket innebär att när event triggas på t ex. en DIV så "bubblar" eventet upp genom DOMen och når till slut document, såvida du ej medvetet stängt av JavaScripts naturliga event bubbling då d.v.s. Praktiken att göra på detta viset brukar kallas "event delegation". Finns många duktiga JavaScript kodare som förespråkar detta framför alternativet att fästa direkt på element du vill avlyssna klick event för.
- Läs mer om Event Delegation hos David Walsh här
- Läs mer om Event Bubbling här hos Mozilla Developer Network (MDN)
Gällande HTML style="" attribut
Tänk också på style-attribut för HTML-element bör också undvikas on-page på produktionssidor så mycket det går då detta också:
- Kluddar upp HTML-koden
- Slösar Bytes (större filstorlekar = längre laddningstider)
- Försvårar framtida underhåll
Det är helt enkelt inte lika effektivt rent allmänt som att ha sin CSS kod samlad i ett externt CSS-dokument för sin sida, alternativt flera olika uppdelade beroende på om man vill begränsa mängden render-blockerande CSS-kod som laddas in på varje undersida av sin hemsida.
Varje tecken du skriver i dina koddokument motsvarar 1 Byte lagringsutrymme
Tänk på att varje tecken i dina kod-dokument motsvarar 1 Byte. Generellt är klassnamn kortare än style="display:none;" där du dessutom kan återanvända samma attribut:attributvärde kombo upprepade gånger istället för att upprepa sig och slösa tecken och Byte i onödan.
Above-the-fold CSS Style-block HTML-element undantag för on-page CSS i vissa fall
On-page CSS-style block kan ibland rekommenderas för above-the-fold snabb inladdning av den absolut mest essentiella CSS-koden som berör delarna av hemsidan som syns för besökaren direkt när de besöker din sida, för att tjäna prestanda. Vilket också kan vara ett bra tips att ha i åtanke :)
Undvik så långt det går genererande av DOM-element likaså flytt av DOM-element via JS för prestanda
Ytterligare ett tips är att försöka hålla JS skapande av HTML element till minimum då dessa också är rätt så prestandatyngande processer. Har du tillgång till HTML-koden och har möjlighet att preppa så långt det går så gör det. Alternativt använd JavaScripts createDocumentFragment för att optimalt prestandamässigt flytta element och liknande i DOM:en för din sida.
Rekommenderar Mozilla Developer Network som referenssida för HTML, CSS och JavaScript
Kan för övrigt också varmt rekommendera MDN som primär referens för när ni kollar upp JavaScript kod medan ni håller på och utvecklar, Googla på "MDN documentFragment" eller dylikt t ex. så brukar det komma upp direkt, supersmidigt och har ännu ej hittat likvärdig referenssida som kan mäta sig med Mozillas egna. Grymt bra sida! Funkar även att hänvisa till för HTML och CSS. Finns även väldigt många bra och intressanta artiklar numera för Webbsäkerhet etc. om det blir relevant eller skulle vara av intresse.
Gällande jQuery kod
För jQuery kod som skrivits om tidigare här i tråden bör man också ha i åtanke att jQuery biblioteken tar upp x antal Byte i storlek beroende på antalet funktioner du valt att inkludera, oavsett om du valt att använda det minifierade biblioteket eller ej (som enbart innebär att whitespace reducerats och ev. variabler anonymiserats till kortare varianter för att spara Byte etc.), som vid inkludering på din sida måste läsas in - hela biblioteket - innan dess delar är tillgängliga för användning och ofta använder man bara en bråkdel av alla funktioner som finns inbakade, vilket är varför Vanilla JavaScript brukar vara ett föredraget- och rekommenderat alternativ när man senare börjar webboptimera för prestanda på sin sida. Vilket för samtliga sidor med högt tryck blir relevant förr eller senare.
Vi skrev om all vår jQuery kod på en e-handelssida till Vanilla JS för att Google inte skulle straffa oss sökmotormässigt typ i takt med att Google Core Web Vitals lanserades där mätvärden som LCP (Large Contentful Paint), CLS (Cumulative Layout Shift), m.fl. introducerades som riktlinjer för vad som räknades som "bra sida" i mån av hur snabbt den laddade och hur bra användarupplevelse sidan bidrog med.
jQuery kan för övrigt ibland spara tid temporärt men kan straffa sig som sagt i mån av för prestanda och blir sällan försvarsbart när man behöver varje sekund av sin sidas inladdning jämfört med de "renare" och "lättare" Vanilla JS alternativen.
ECMAScript Strict Mode (Om möjligt! - För prestanda)
Om din hemsidas setup (servermiljö osv.) stödjer det bör du överväga ECMAScript strict mode för bättre prestanda gains jämfört med vanlig loose JavaScript.
Strict mode underlättar för webbläsaren när den tolkar din kod så den kan köras snabbare och minimerar risken för buggar och fel. Detta då det likt XHTML 1.0 Strict en gång i tiden, när det var aktuellt, "tvingade" (in a good way) kodaren av hemsidan att följa en striktare standard som producerade stabilare och bättre hemsidor rent kodmässigt.
Bara lite tankar när jag läste igenom ovan tråd och svaren som skrivits till den :)
Hoppas det landar väl, vill bara bidra med lite insikter jag fått "den hårda vägen" från JavaScript-världen under de senaste 5+ åren som full-stack webbutvecklare för ett antal e-handelssidor med periodvis väldigt högt tryck som pressat kraven på hur vi utvecklade sidorna. Där har gjorts en hel del research genom åren ^^
Lycka till med era JavaScript-eskapader och önskar er alla Allt Gott! :)