Issue
I want to make an infinite carousel in javascript. When the elements go off-screen, I clone them and paste them at the end of the list. But after a minute there are a lot of cloned elements in the HTML layout. I decided to delete this element after cloning. But I get an instant offset of all elements. How to avoid it? Or maybe there is another algorithm on how to implement this endless carousel?
Here's the code https://codepen.io/alessandro-kex/pen/abGWNEK
window.addEventListener("load", function () {
const slideContainer = document.querySelector(".carousel");
const slidesWrapper = document.querySelector(".carousel-slides");
let slides = document.querySelectorAll(".carousel-slide");
let index = 0;
const interval = 1500;
let moveDistance = 0;
const paddingRight = 50;
let lastSlideIndex = slides.length - 1;
let firstClone;
const startSlide = (index) => {
this.setInterval(() => {
moveDistance = moveDistance + slides[index].clientWidth + paddingRight;
slidesWrapper.style.transform = `translateX(${-moveDistance}px)`;
slidesWrapper.style.transition = "1s";
firstClone = slides[index].cloneNode(true);
firstClone.id = `first-clone-${index}`;
slidesWrapper.append(firstClone);
/*If uncomment it - then the problem starts */
//slides[index].remove();
index++;
}, interval);
};
startSlide(index);
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.carousel {
margin: 0 auto;
width: 100%;
position: relative;
}
.carousel-slides {
display: flex;
list-style: none;
gap: 50px;
flex-shrink: 1;
}
.carousel-slide {
position: relative;
min-width: 0;
flex-shrink: 0;
}
.carousel-slide {
height: 100px;
display: flex;
align-items: center;
justify-content: center;
min-width: 0;
}
.carousel-item-text {
white-space: nowrap;
}
.carousel-item-img {
width: 100px;
height: auto;
}
.round {
padding: 30px 50px;
border-radius: 120px;
}
.light-blue {
background-color: #d8f1ff;
}
.pink {
background-color: #ffeaf0;
}
.purpule {
background-color: #eae9ff;
}
<div class="carousel">
<ul class="carousel-slides">
<li class="carousel-slide" data-number="0">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide light-blue round" data-number="1">
<span class="carousel-item-text">11111111 1111 <br> 111111111</span>
</li>
<li class="carousel-slide">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide pink round">
<span class="carousel-item-text">22222 22222 <br> 222222222 2222222222 222222222</span>
</li>
<li class="carousel-slide">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide light-blue round">
<span class="carousel-item-text">333 333333333 <br> 333333333333</span>
</li>
<li class="carousel-slide">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide purpule round">
<span class="carousel-item-text">4444 444444444444<br> 44444</span>
</li>
<li class="carousel-slide">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide pink round">
<span class="carousel-item-text">55555555 55555<br> 55 5555</span>
</li>
<li class="carousel-slide">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide pink round">
<span class="carousel-item-text">6666666 6666666666 <br> 66666 6666666 66666</span>
</li>
<li class="carousel-slide">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide light-blue round">
<span class="carousel-item-text">777777 777 777<br> 77 77777</span>
</li>
<li class="carousel-slide">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide purpule round" data-number="16">
<span class="carousel-item-text">888 8888<br> 88888888</span>
</li>
</ul>
</div>
Solution
For this kind of thing you should familiarize yourself with promises
otherwise the idea is the right one,
1 - make a translateX with a transition time
2 - once the transition is finished remove the transition time
3 - put the first element at the end and reset the translateX to zero
4 - start again...
complete code :
(async ()=> // async IIFE code for slider.
{
const
interval = 1500 // ms
, paddingRight = 50
, slideContainer = document.querySelector('.carousel')
, slidesWrapper = document.querySelector('.carousel-slides')
, slides = document.querySelectorAll('.carousel-slides > li')
, delay = ms => new Promise(r => setTimeout(r, ms))
, movLeft = (el, mov) => new Promise(r =>
{
el.ontransitionend =_=>
{
el.ontransitionend = null
el.style.transition = 'none';
r()
}
el.style.transition = '1s';
el.style.transform = `translateX(${-mov}px)`;
});
let index = 0;
while (true) // infinite carrousel loop
{
await delay( interval )
await movLeft( slidesWrapper, slides[index].clientWidth + paddingRight )
slidesWrapper.appendChild( slides[index] ) // mov first slide to the end
slidesWrapper.style.transform = `translateX(0)` // rest translateX
index = ++index % slides.length
}
})()
* {
margin : 0;
padding : 0;
box-sizing : border-box;
}
.carousel {
margin : 0 auto;
width : 100%;
position : relative;
}
.carousel-slides {
display : flex;
list-style : none;
gap : 50px;
flex-shrink : 1;
}
.carousel-slide {
position : relative;
min-width : 0;
flex-shrink : 0;
height : 100px;
display : flex;
align-items : center;
justify-content : center;
min-width : 0;
}
.carousel-item-text {
white-space : nowrap;
}
.carousel-item-img {
width : 100px;
height : auto;
}
.round {
padding : 30px 50px;
border-radius : 120px;
}
.light-blue {
background-color : #d8f1ff;
}
.pink {
background-color : #ffeaf0;
}
.purpule {
background-color : #eae9ff;
}
<div class="carousel">
<ul class="carousel-slides">
<li class="carousel-slide" data-number="0">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide light-blue round" data-number="1">
<span class="carousel-item-text">11111111 1111 <br> 111111111</span>
</li>
<li class="carousel-slide">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide pink round">
<span class="carousel-item-text">22222 22222 <br> 222222222 2222222222 222222222</span>
</li>
<li class="carousel-slide">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide light-blue round">
<span class="carousel-item-text">333 333333333 <br> 333333333333</span>
</li>
<li class="carousel-slide">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide purpule round">
<span class="carousel-item-text">4444 444444444444<br> 44444</span>
</li>
<li class="carousel-slide">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide pink round">
<span class="carousel-item-text">55555555 55555<br> 55 5555</span>
</li>
<li class="carousel-slide">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide pink round">
<span class="carousel-item-text">6666666 6666666666 <br> 66666 6666666 66666</span>
</li>
<li class="carousel-slide">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide light-blue round">
<span class="carousel-item-text">777777 777 777<br> 77 77777</span>
</li>
<li class="carousel-slide">
<img src="https://via.placeholder.com/150" alt="" class="carousel-item-img">
</li>
<li class="carousel-slide purpule round" data-number="16">
<span class="carousel-item-text">888 8888<br> 88888888</span>
</li>
</ul>
</div>
new version for multiple carousels... (2022/09/20)
'use strict';
class carouselClass
{
static #interval = 1500;
static #paddingRight = 50;
#slidesWrapper;
#slides;
#Li_index;
#onLoop;
constructor(UL_Carousel)
{
this.#slidesWrapper = UL_Carousel;
this.#slides = UL_Carousel.querySelectorAll(`li`);
this.#Li_index = 0;
this.#onLoop = false;
}
#delay( ms )
{
return new Promise(resolve => setTimeout(resolve, ms));
}
#movLeft( mov, indx )
{
return new Promise(resolve =>
{
this.#slidesWrapper.ontransitionend =()=>
{
this.#slidesWrapper.ontransitionend = null;
this.#slidesWrapper.style = '';
this.#slidesWrapper.appendChild( this.#slides[this.#Li_index] ); // mov slide to the end
this.#Li_index = ++this.#Li_index % this.#slides.length; // next Li element index
resolve();
}
this.#slidesWrapper.style.transition = '1s';
this.#slidesWrapper.style.transform = `translateX(${mov}px)`;
});
}
async run()
{
this.#onLoop = true;
this.#slidesWrapper.style = '';
while( this.#onLoop ) // infinite carrousel loop
{
await this.#delay( carouselClass.#interval );
await this.#movLeft( -(this.#slides[this.#Li_index].clientWidth + carouselClass.#paddingRight) );
}
}
stop()
{
this.#onLoop = false;
}
}
const carousels = [...document.querySelectorAll('.carousel')]
.map( cBox =>
({ box : cBox
, cls : new carouselClass( cBox.querySelector('ul.carousel-slides') )
}))
carousels.index = -1;
carousels.animateNext =_=>
{
carousels.index = ++carousels.index % carousels.length;
carousels.forEach((crl,i)=> crl.box.classList.toggle('noDisplay', carousels.index !== i) );
carousels[carousels.index].cls.run();
}
carousels.animateNext(); // first attempt...
bt_switch.onclick =_=>
{
carousels[carousels.index].cls.stop(); // stop infinite loop on current carousel
carousels.animateNext();
}
* {
margin : 0;
padding : 0;
box-sizing : border-box;
}
.carousel {
margin : 0 auto;
width : 100%;
position : relative;
overflow : hidden;
}
.carousel-slides {
display : flex;
list-style : none;
gap : 50px;
flex-shrink : 1;
}
.carousel-slides img {
height: 100px;
}
.carousel-slides span {
display : inline-block;
white-space : nowrap;
padding : 30px 50px;
border-radius : 120px;
}
.light-blue { background-color : #d8f1ff; }
.pink { background-color : #ffeaf0; }
.purpule { background-color : #eae9ff; }
.noDisplay { display : none; }
<div class="carousel">
<ul class="carousel-slides">
<li> <img src="https://picsum.photos/150/150?random=1"> </li>
<li> <span class="light-blue">11111111 1111 <br> 111111111</span></li>
<li> <img src="https://picsum.photos/150/150?random=2"> </li>
<li> <span class="pink">2222222 2222 222 <br> 22</span></li>
<li> <img src="https://picsum.photos/150/150?random=3"> </li>
<li> <span class="light-blue">33 33 <br> 333 33 33 33 333 33 33 33</span></li>
<li> <img src="https://picsum.photos/150/150?random=4"> </li>
<li> <span class="purpule"> 444444 444 44 4<br> 44 44 44 4444 </span></li>
<li> <img src="https://picsum.photos/150/150?random=5"> </li>
<li> <span class="pink"> 555555 55 <br>555 555 </span></li>
<li> <img src="https://picsum.photos/150/150?random=6"> </li>
<li> <span class="pink"> 66666666666666666666 <br> 6 </span></li>
<li> <img src="https://picsum.photos/150/150?random=7"> </li>
<li> <span class="light-blue"> 77777777 777777777 777777<br> 77777777777777777 77777777777777777</span></li>
<li> <img src="https://picsum.photos/150/150?random=8"> </li>
<li> <span class="purpule"> 88 888 <br> 8 8 8 8 8</span></li>
</ul>
</div>
<div class="carousel">
<ul class="carousel-slides">
<li> <img src="https://picsum.photos/150/150?random=9"> </li>
<li> <span class="light-blue">aaa <br> 11</span></li>
<li> <img src="https://picsum.photos/150/150?random=10"> </li>
<li> <span class="pink">bbb bbb <br> 22</span></li>
<li> <img src="https://picsum.photos/150/150?random=11"> </li>
<li> <span class="light-blue">ccc <br> 3</span></li>
<li> <img src="https://picsum.photos/150/150?random=12"> </li>
<li> <span class="purpule"> ddd ddd <br> 4 </span></li>
<li> <img src="https://picsum.photos/150/150?random=13"> </li>
<li> <span class="pink"> eee eee eee <br> 5 </span></li>
<li> <img src="https://picsum.photos/150/150?random=14"> </li>
<li> <span class="pink"> ff ff ff <br> 6 </span></li>
<li> <img src="https://picsum.photos/150/150?random=15"> </li>
<li> <span class="light-blue"> g<br> g gg g gg g gg</span></li>
</ul>
</div>
<br><br>
<button id="bt_switch">___ carousel switcher ___</button>
Answered By - Mister Jojo
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.