Creating dots with JavaScript
Da sich die Anzahl der Slides ändern kann, muss sich die Anzahl der Dots ebenfalls ändern. Diese ist im Moment hardcoded im HTML, was nicht besonders effizient ist. Wir wollen daher den gesamten Dot-Navigationsbereich mit JavaScript erstellen.
Removing old code
Section titled “Removing old code”Zuerst entfernen wir den Bereich aus dem HTML:
<div class="carousel-dots"> <button class="carousel-dot is-selected"></button> <button class="carousel-dot"></button> <button class="carousel-dot"></button></div>und diesen aus dem JavaScript:
const dotsContainer = carousel.querySelector('.carousel-dots');const dots = [...carousel.querySelectorAll('.carousel-dot')];Creating the dots
Section titled “Creating the dots”Als erstes erstellen wir eine Funktion createDots. Diese soll das HTML, das wir oben rausgelöscht haben, erzeugen. Dazu verwenden wir die Methode createElement() und classList.add:
function createDots() { const dotsContainer = document.createElement('div'); dotsContainer.classList.add('carousel-dots');}Um die Buttons zu erzeugen, loopen wir über die Slides. So erhalten wir pro Slide einen Button:
function createDots() { // ... slides.forEach(slide => { const dot = document.createElement('button'); dot.classList.add('carousel-dot'); });}Nun fügen wir die Buttons mit der Methode appendChild() dem zuvor erstellten dotsContainer hinzu:
function createDots() { // ... slides.forEach(slide => { const dot = document.createElement('button'); dot.classList.add('carousel-dot'); dotsContainer.appendChild(dot); });}Als nächstes brauchen wir noch die Klasse is-selected auf dem ersten Dot. Dafür gibt es zwei Möglichkeiten:
- Wir können den Index verwenden, also
dot[0] - oder prüfen, ob der Slide die Klasse
is-selectedenthält.
Beide Methoden funktionieren, aber die zweite ist robuster, weil damit der Slider auch beim zweiten Slide beginnen kann.
function createDots() { // ... slides.forEach(slide => { const dot = document.createElement('button'); dot.classList.add('carousel-dot');
if (slide.classList.contains('is-selected')) { dot.classList.add('is-selected'); }
dotsContainer.appendChild(dot); });}Zuletzt geben wir dotsContainer aus der Funktion zurück. Somit können wir dotsContainer nutzen wo wir wollen.
function createDots() { // ... return dotsContainer;}Using createDots
Section titled “Using createDots”Um den DotContainer mit den Dots zu erstellen, müssen wir
- die Variable
dotsContainerdeklarieren und die Funktion aufrufen - die Variable
dotsdeklarieren und - den neu erstellten Container ins DOM einfügen
// declare the variablesconst slides = [...carousel.querySelectorAll('.carousel-slide')];const dotsContainer = createDots(slides);const dots = [...dotsContainer.children];
// declare the functionsfunction createDots(slides);// ...
// add the dotsContainer and the dots to the DOMsetSlidePositions();carousel.appendChild(dotsContainer);Cleaning up
Section titled “Cleaning up”Unsere Funktion createDots() benötigt die Slides. Wir müssen sicherstellen, dass die Slides vorhanden sind, bevor wir createDots() aufrufen. Sie muss aber vor der Deklaration der Variable für den DotContainer stehen. Das ergibt eine ungute Mischung: zuerst Variablendeklarationen, dann eine Funktion, dann weitere Variablen. Das wollen wir vermeiden.
Im Moment funktioniert das Skript, weil slides vor der Verwendung von createDots() deklariert wurde. Wir sagen: slides ist im lexical scope`.
Wenn wir slides und createDots() vertauschen, funktioniert das Skript nicht mehr. Wenn wir externe Variable verwenden, wird Code fragil. Wenn wir der Funktion createDots() slides als Argument mitgeben, sehen wir auf einen Blick, dass die Deklaration von dotsContainer nach der Deklaration von slides kommen muss.
We’ve been relying on external variables
Section titled “We’ve been relying on external variables”Bei jeder Funktion im Carousel haben wir uns auf externe Variable (und somit auf den lexical scope) verlassen. Das hat funktioniert, weil alle Variablen vorab deklariert wurden.
Hoisting
Section titled “Hoisting”Als wir (kurzzeitig) die Funktion createDots() an den Anfang unseres JavaScript-Files gebracht haben, haben wir die Funktion quasi manuell “gehoisted”. Indem wir eine normale Funktion verwenden und der Funktion einen Parameter bzw. beim Aufruf das benötigte Argument mitgeben, passiert das automatisch. So können wir alle Variable und Funktionen sauber und getrennt voneinander im Code “aufheben”.
// Declaring all variables// ...const slides = [...carousel.querySelectorAll('.carousel-slide')];const dotsContainer = createDots();const dots = [...dotsContainer.children];
// Declaring all functionsfunction createDots(slides) { // ...}// ...Addendum meine Dot-Lösung
Section titled “Addendum meine Dot-Lösung”Nicht elegant, weil keine Funktion, funzt aber trotzdem:
const dotList = slides.map(slide => `<button class="carousel-dot"></button>`).join('');dotsContainer.innerHTML = dotList;const dots = [...carousel.querySelectorAll('.carousel-dot')];const firstDot = dots[0];firstDot.classList.add('is-selected');