I’m a beginner in javascript. I downloaded a custom javacsript slide from this website:
https://www.cssscript.com/swiper-thumbnail-paginator/
Slide demo here: https://www.cssscript.com/demo/swiper-thumbnail-paginator/
I’ve also created a demo on jsfiddle: https://jsfiddle.net/t4c1nb3g/
The file consists of 5 files, namely: index.html, style.css, debounce.js, script.js, slide.js
And it has 6 images.
Currently, there is no slide loop in the demo, I want to change it to play the slides continuously (looping).
How can I make it loop for the slide?
Below is the index.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Slider</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="slide-wrapper">
<ul class="slide">
<li><img src="https://i.stack.imgur.com/2fkLR.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/gN1Ri.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/FgqYP.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/su1na.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/vZYry.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/5dXtQ.jpg" alt=""></li>
</ul>
</div>
<div class="wrap-controls">
<div class="arrow-nav">
<button class="prev"></button>
</div>
<ul class="custom-controls">
<li><img src="https://i.stack.imgur.com/2fkLR.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/gN1Ri.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/FgqYP.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/su1na.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/vZYry.jpg" alt=""></li>
<li><img src="https://i.stack.imgur.com/5dXtQ.jpg" alt=""></li>
</ul>
<div class="arrow-nav">
<button class="next"></button>
</div>
</div>
<script type="module" src="js/script.js"></script>
</body>
</html>
Below is the style.css file:
body {
margin: 0px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
ul {
padding: 0px;
margin: 0px;
list-style: none;
}
img {
display: block;
max-width: 100%;
}
.slide-wrapper {
overflow: hidden;
}
.slide {
display: flex;
}
.slide:hover {
will-change: transform;
}
.slide li {
flex-shrink: 0;
max-width: 600px;
margin: 0 20px;
border-radius: 4px;
overflow: hidden;
box-shadow: 0 2px 4px rgba(0,0,0,.4);
opacity: .8;
transform: scale(.8);
transition: .4s;
}
.slide li.active {
opacity: 1;
transform: scale(1);
}
[data-control="slide"] {
display: flex;
justify-content: center;
margin-top: 20px;
}
[data-control="slide"] li a {
display: block;
width: 12px;
height: 12px;
background: #FB5;
border-radius: 50%;
overflow: hidden;
text-indent: -999px;
margin: 5px;
}
[data-control="slide"] li.active a, [data-control="slide"] li a:hover {
background: #E54;
}
.custom-controls {
display: flex;
justify-content: center;
margin-top: 40px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.custom-controls li {
opacity: .8;
transform: scale(.8);
width: 40px;
height: 40px;
border-radius: 50%;
overflow: hidden;
margin: 2px;
box-shadow: 0 2px 2px rgba(0,0,0,.5);
transition: .3s;
cursor: pointer;
}
.custom-controls li.active {
opacity: 1;
transform: scale(1);
}
.arrow-nav {
display: flex;
justify-content: space-around;
margin: 20px 10px 0 10px;
}
.arrow-nav button {
cursor: pointer;
border: none;
border-radius: 50%;
color: white;
width: 30px;
height: 30px;
background: #999 url('../img/arrow.svg') center center no-repeat;
outline: none;
}
.arrow-nav button:hover {
background: #333 url('../img/arrow.svg') center center no-repeat;
transition: ease-in-out .3s;
}
.arrow-nav button.prev {
transform: rotate(-180deg);
}
.wrap-controls {
display: flex;
justify-content: center;
align-items: center;
}
Below is the debounce.js file:
export default function debounce(callback, delay) {
let timer;
return (...args) => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
callback(...args);
timer = null;
}, delay);
};
}
Below is the script.js file:
import SlideNav from './slide.js';
const slide = new SlideNav('.slide', '.slide-wrapper');
slide.init();
slide.addArrow('.prev', '.next');
slide.addControl('.custom-controls');
Below is the slide.js file:
import debounce from './debounce.js';
export class Slide {
constructor(slide, wrapper) {
this.slide = document.querySelector(slide)
this.wrapper = document.querySelector(wrapper);
this.dist = { finalPosition: 0, startX: 0, movement: 0 }
this.activeClass = 'active';
this.changeEvent = new Event('changeEvent');
}
transition(active) {
this.slide.style.transition = active ? 'transform .3s' : '';
}
moveSlide(distX) {
this.dist.movePosition = distX;
this.slide.style.transform = `translate3d(${distX}px, 0, 0)`;
}
updatePosition(clientX) {
this.dist.movement = (this.dist.startX - clientX) * 1.6;
return this.dist.finalPosition - this.dist.movement;
}
onStart(event) {
let movetype;
if (event.type === 'mousedown') {
event.preventDefault();
this.dist.startX = event.clientX;
movetype = 'mousemove';
} else {
this.dist.startX = event.changedTouches[0].clientX;
movetype = 'touchmove';
}
this.wrapper.addEventListener(movetype, this.onMove);
this.transition(false);
}
onMove(event) {
const pointerPosition = (event.type === 'mousemove') ? event.clientX : event.changedTouches[0].clientX;
const finalPosition = this.updatePosition(pointerPosition);
this.moveSlide(finalPosition);
}
onEnd(event) {
const movetype = (event.type === 'mouseup') ? 'mousemove' : 'touchmove';
this.wrapper.removeEventListener(movetype, this.onMove);
this.dist.finalPosition = this.dist.movePosition;
this.transition(true);
this.changeSlideOnEnd();
}
changeSlideOnEnd() {
if (this.dist.movement > 120 && this.index.next !== undefined) {
this.activeNextSlide();
} else if (this.dist.movement < -120 && this.index.prev !== undefined) {
this.activePrevSlide();
} else {
this.changeSlide(this.index.active);
}
}
addSlideEvents() {
this.wrapper.addEventListener('mousedown', this.onStart);
this.wrapper.addEventListener('touchstart', this.onStart);
this.wrapper.addEventListener('mouseup', this.onEnd);
this.wrapper.addEventListener('touchend', this.onEnd);
}
// Slides config
slidePosition(slide) {
const margin = (this.wrapper.offsetWidth - slide.offsetWidth) / 2;
return -(slide.offsetLeft - margin);
}
slidesConfig() {
this.slideArray = [...this.slide.children].map((element) => {
const position = this.slidePosition(element);
return { position, element };
});
}
slidesIndexNav(index) {
const last = this.slideArray.length - 1;
this.index = {
prev: index ? index - 1 : undefined,
active: index,
next: index === last ? undefined : index + 1,
}
}
changeSlide(index) {
const activeSlide = this.slideArray[index];
this.moveSlide(activeSlide.position);
this.slidesIndexNav(index);
this.dist.finalPosition = activeSlide.position;
this.changeActiveClass();
this.wrapper.dispatchEvent(this.changeEvent);
}
changeActiveClass() {
this.slideArray.forEach(item => item.element.classList.remove(this.activeClass));
this.slideArray[this.index.active].element.classList.add(this.activeClass);
}
activePrevSlide() {
if (this.index.prev !== undefined) this.changeSlide(this.index.prev);
}
activeNextSlide() {
if (this.index.next !== undefined) this.changeSlide(this.index.next);
}
onResize() {
setTimeout(() => {
this.slidesConfig();
this.changeSlide(this.index.active);
}, 1000);
}
addResizeEvent() {
window.addEventListener('resize', this.onResize);
}
bindEvents() {
this.onStart = this.onStart.bind(this);
this.onMove = this.onMove.bind(this);
this.onEnd = this.onEnd.bind(this);
this.activePrevSlide = this.activePrevSlide.bind(this);
this.activeNextSlide = this.activeNextSlide.bind(this);
this.onResize = debounce(this.onResize.bind(this), 200);
}
init() {
this.bindEvents();
this.transition(true);
this.addSlideEvents();
this.slidesConfig();
this.addResizeEvent();
this.changeSlide(0);
return this;
}
}
export default class SlideNav extends Slide {
constructor(slide, wrapper) {
super(slide, wrapper);
this.bindControlEvents();
}
addArrow(prev, next) {
this.prevElement = document.querySelector(prev);
this.nextElement = document.querySelector(next);
this.addArrowEvent();
}
addArrowEvent() {
this.prevElement.addEventListener('click', this.activePrevSlide);
this.nextElement.addEventListener('click', this.activeNextSlide);
}
createControl() {
const control = document.createElement('ul');
control.dataset.control = 'slide';
this.slideArray.forEach((item, index) => {
control.innerHTML += `<li><a href="#slide${index + 1}">${index + 1}</a></li>`;
});
this.wrapper.appendChild(control);
return control;
}
eventControl(item, index) {
item.addEventListener('click', (event) => {
event.preventDefault();
this.changeSlide(index);
});
this.wrapper.addEventListener('changeEvent', this.activeControlItem);
}
activeControlItem() {
this.controlArray.forEach(item => item.classList.remove(this.activeClass));
this.controlArray[this.index.active].classList.add(this.activeClass);
}
addControl(customControl) {
this.control = document.querySelector(customControl) || this.createControl();
this.controlArray = [...this.control.children];
this.activeControlItem();
this.controlArray.forEach(this.eventControl);
}
bindControlEvents() {
this.eventControl = this.eventControl.bind(this);
this.activeControlItem = this.activeControlItem.bind(this);
}
}
Thank you very much,
best regards.
Franks.