Es geht auch ohne Javascript Framework
oder wie baut man eine Karusel mit (Vanilla) Javascript
Über mich
-
Robert Mittl
-
Stuttgart, Germany
-
selbständig seit 2012
-
Web Entwickler
-
JUG Stuttgart
E-Mail: info@mittl-medien.de
Twitter: @mittlmedien
JS Frameworks und Libraries
Drei Fraktionen:
-
Hey Cool: React, Vue, Angular 😎
-
Weinende: ich will nicht ohne jQuery 😫
-
Oh Sch..: Javscript 💩
Hello World!
ist mit Frameworks
- oft sehr einfach
-
bei größeren Projekten wird komplex 😬
Javascript lernen
-
scheint Anfangs schwierig
-
grundlegendes Lernen - Step bei Step
-
nicht "Wissen" stellt eine Hürde da
-
erlerntes Wissen hilft auch bei den Frameworks
Toolset
-
Editor
-
beschäftigt euch nicht Code einzurücken
-
benutzt Spellchecker
-
anständiger Browser
Debugging
-
Tastaturkürzel für console.log()
-
im Browser selbst
-
Chrome Debugging über Node
Chrome Debugging über Node
-
im Terminal
- in der Browserzeile chrome://inspect/
node --inspect-brk index.js
am Praxisbeispiel lernen 👨🎓👩🎓
-
Aufbau Step by Step
-
Verständis der Zusammenhänge einfacher
-
viele Wege führen nach Rom
-
Ziel, Grundverständis von Javascript zu vermitteln
-
kann dann nach belieben erweitert werden
-
wäre später einfach als "Custom Modul" in Joomla zu integrieren
Code Bilder
<div class="carousel__track-container">
<ul class="carousel__track">
<li class="carousel__slide is-selected">
<a href="#" style="background-image: url('images/carousel_image_1.jpg')"></a>
</li>
<li class="carousel__slide">
<a href="#" style="background-image: url('carousel_image_2.jpg')"></a>
</li>
<li class="carousel__slide">
<a href="#" style="background-image: url('carousel_image_3.jpg')"></a>
</li>
<li class="carousel__slide">
<a href="#" style="background-image: url('carousel_image_4.jpg')"></a>
</li>
</ul>
</div>
Bilder
absolut nebeneinander positioniert
Navigation / Status Joomla Logo
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 398.7 398.2">
<title>
Joomla!-Logo
</title>
<path id="j-green" d="M85.1,213.7l-7.5-7.4c-23.9-23.9-30.8-57.4-22.3-87"
class="joomla-logo-1 is-selected" transform="translate(-13.8 -13.3)" />
<path id="j-orange" d="M129.2,17"
class="joomla-logo-2" transform="translate(-13.8 -13.3)" />
<path id="j-red" d="M306.2,368.4c-3.2,368.4Z"
class="joomla-logo-3" transform="translate(-13.8 -13.3)" />
<path id="j-blue" d="M290.8,257....."
class="joomla-logo-4" transform="translate(-13.8 -13.3)" />
</svg>
Left und Right Button
<button class="carousel__button">
<svg >
......
</svg>
</button>
Positionierung der Bilder mit JS
const track = document.querySelector('.carousel__track')
const slides = Array.from(track.children)
console.log('slides', slides)
const rect = slides[0].getBoundingClientRect()
const slideWidth = rect.width
console.log('slideWidth', slideWidth)
Positionierung der Bilder mit JS
const slideWidth = slides[0].getBoundingClientRect().width
slides[0].style.left = slideWidth * 0 + 'px'
slides[1].style.left = slideWidth * 1 + 'px'
slides[2].style.left = slideWidth * 2 + 'px'
slides[3].style.left = slideWidth * 3 + 'px'
Positionierung der Bilder mit JS
slides.forEach((slide, index) => {
slide.style.left = slideWidth * index + 'px'
})
const slideWidth = slides[0].getBoundingClientRect().width
slides[0].style.left = slideWidth * 0 + 'px'
slides[1].style.left = slideWidth * 1 + 'px'
slides[2].style.left = slideWidth * 2 + 'px'
slides[3].style.left = slideWidth * 3 + 'px'
Click -> nächste Bild
nextButton.addEventListener('click', e => {
const currentSlide = track.querySelector('.is-selected')
const nextSlide = currentSlide.nextElementSibling
const movingWidth = nextSlide.style.left
console.log('movingWidth', movingWidth)
})
nextButton.addEventListener('click', e => {
//..
track.style.left = '-' + movingWidth
})
Click -> nächste Bilder
nextButton.addEventListener('click', e => {
//...
currentSlide.classList.remove('is-selected')
nextSlide.classList.add('is-selected')
})
nach dem letzten Slide
Abhilfe Ausblenden des Buttons
nextButton.addEventListener('click', e => {
//...
const isLastSlide = !nextSlide.nextElementSibling
if (isLastSlide) {
nextButton.classList.add('is-hidden')
}
})
.is-hidden {
display: none;
}
CSS
Update Joomla Logo
nextButton.addEventListener('click', e => {
//...
const isLastSlide = !nextSlide.nextElementSibling
if (isLastSlide) {
nextButton.classList.add('is-hidden')
}
})
.is-hidden {
display: none;
}
CSS
🥳 erster Schritt
nächster Schritt Code kopieren
Änderung des 'nextButton' to 'backButton'
const backButton = document.querySelector('.back')
backButton.addEventListener('click', e => {
const currentSlide = track.querySelector('.is-selected')
const backSlide = currentSlide.previousElementSibling
const movingWidth = backSlide.style.left
track.style.left = '-' + movingWidth
currentSlide.classList.remove('is-selected')
backSlide.classList.add('is-selected')
const isLastSlide = !backSlide.previousElementSibling
if (isLastSlide) {
backButton.classList.add('is-hidden')
}
const currentLogoPart = joomlaLogo.querySelector('.is-selected')
const backLogoPart = currentLogoPart.previousElementSibling
currentLogoPart.classList.remove('is-selected')
backLogoPart.classList.add('is-selected')
})
Joomla Rotation Logo
joomlaLogo.addEventListener('click', e => {
const clickPath = e.target.closest('path')
console.log('clickPath', clickPath)
})
Verwendung Event Delegation Pattern
- matches
- closest
Current Slide
joomlaLogo.addEventListener('click', e => {
const clickPath = e.target.closest('path')
if (clickPath) {
const currentPath = clickPath.querySelector('.is-selected')
const currentSlide = track.querySelector('.is_selected')
const targetPath = clickPath
}
})
Joomla Logo indexieren
for (let index = 0; index < paths.length; index++) {
if (paths[index] === targetPath) {
targetIndex = index - 1
}
}
const targetSlide = slides[targetIndex]
um das Zielslide zu herauszufinden
const paths = Array.from(joomlaLogo.children)
im joomlaLogo Listener
Slide ändern/bewegen
const targetSlide = slides[targetIndex]
const movingWidth = targetSlide.style.left
track.style.left = '-' + movingWidth
currentSlide.classList.remove('is-selected')
targetSlide.classList.add('is-selected')
currentPath.classList.remove('is-selected')
targetPath.classList.add('is-selected')
zusätzlich Select-Status ändern
Buttons ausblenden
if (targetIndex === 0) {
backButton.classList.add('is-hidden')
nextButton.classList.remove('is-hidden')
} else if (targetIndex === slides.length - 1) {
backButton.classList.remove('is-hidden')
nextButton.classList.add('is-hidden')
} else {
backButton.classList.remove('is-hidden')
nextButton.classList.remove('is-hidden')
} const targetSlide = slides[targetIndex]
}
Buttons zeigen
backButton.addEventListener('click', e => {
nextButton.classList.remove('is-hidden')
}
nextButton.addEventListener('click', e => {
backButton.classList.remove('is-hidden')
}
wenn wir auf den zurück oder nächste klicken
Slides animieren
track.style.left = '-' + movingWidth
ersetzen von
mit
track.style.transform = `translateX(-${movingWidth})`
CSS
.carousel__track {
transform: translateX(0);
transition: transform 0.3s ease-out;
}
💪 Läuft 🤩
Aber....🤔
es geht bestimmt besser...
setzte Position Slide:
const setSlidePostion = (slide, index) => {
slide.style.left = slideWidth * index + 'px'
}
slides.forEach(setSlidePostion)
Auslagern in Funktionen
Code vereinfachen
nextButton.addEventListener('click', e => {
//...
const movingWidth = nextSlide.style.left
track.style.transform = `translateX(-${movingWidth})`
currentSlide.classList.remove('is-selected')
nextSlide.classList.add('is-selected')
}
Code vereinfachen
const moveSlide = (track, targetSlide, currentSlide) => {
track.style.transform = `translateX(-${targetSlide.style.left})`
currentSlide.classList.remove('is-selected')
targetSlide.classList.add('is-selected')
}
nextButton.addEventListener('click', e => {
//...
moveSlide(track, nextSlide, currentSlide)
}
Early return - Verschachtelungen vermeiden
if (clickPath) {
}
if (!clickPath) return
Logo Farbe updaten
const updateLogoColor = (targetLogoPart, currentLogoPart) => {
currentLogoPart.classList.remove('is-selected')
targetLogoPart.classList.add('is-selected')
}
Buttons ein- und ausblenden
const showHideNextBackButtons = (targetIndex, backButton, nextButton) => {
if (targetIndex === 0) {
backButton.classList.add('is-hidden')
nextButton.classList.remove('is-hidden')
} else if (targetIndex === slides.length - 1) {
backButton.classList.remove('is-hidden')
nextButton.classList.add('is-hidden')
} else {
backButton.classList.remove('is-hidden')
nextButton.classList.remove('is-hidden')
}
}
for Schleife kürzen
let targetIndex
for (let index = 0; index < paths.length; index++) {
if (paths[index] === clickPath) {
targetIndex = index - 1
}
}
const targetIndex = paths.findIndex(path => path === clickPath) - 1
findIndex bietet neue Möglichkeiten
const currentSlide = track.querySelector('.is-selected')
const nextSlide = currentSlide.nextElementSibling
const currentIndexSlide = slides.findIndex(slide => slide.classList.contains('is-selected'))
Scope?
E-Mail: info@mittl-medien.de
Twitter: @mittlmedien
Fragen?
Zell Liew (Javascript Developer zellwk.com, Twitter @zellwk)
Niels Nübel für Fotos (https://www.flickr.com/photos/niels85/)
Danke👏
Es geht auch ohne JS Framework
By Robert Mittl
Es geht auch ohne JS Framework
- 942