javascript – How to make autosliding carousel thumbnail change background image when active

javascript – How to make autosliding carousel thumbnail change background image when active

The question asks for various ideas on how to simplify code and how to use native JavaScript to create a slider that rolls continuously.

The code originally used glider and it may be something simpler would be sufficient to get the desired result, for example using animationend event to change the background when a slide gets to the left hand side. However, eating the elephant slowly Ill tackle the yucky code (part 3) first.

Although the HTML looks rather daunting, 4 calls on a click for every li element for example, it is currently what is required so lets investigate creating it at run time. This gives us more easily maintainable code. For example, if we want to remove a slide, or alter the order of slides or add one we can just alter the slider array defined below and JavaScript will do the rest.

Part 1 of the question asked about sliding. We slide the whole ul element using CSS animation defined something like this, where 33vw is the total width of a slide (inc. margins/padding)

@keyframes sliding0 {
  0% { left: 0; }
  30% { left: 0; }
  100% { left: -33vw; }
}

and we add an event listener to the element to trap animationend events because when the ul has slid one slides width we want to change the hero image, and we want to put the slide that has just disappeared onto the back of the infinie sliding will work. We then set the animation running again.

See the snippet for details on how this and other events are dealt with. It also shows how the changeHero function can work which was part 2 of the question. Note, the snippet works more or less in the SO environment, though occasionally hover action is partially ignored. Running the code on your own machine it should be fine though.

<!DOCTYPE html>
<html>
<head>
<style>

@keyframes sliding0 {
  0% { left: 0; }
  30% { left: 0; }
  100% { left: -33vw; }
}

@keyframes sliding1 {
  0% { left: 0; }
  30% { left: 0; }
  100% { left: -33vw; }
}

body {
  background-repeat: no-repeat no-repeat;
  background-size: cover;
  background-position: center center;
}
div .glide_track {
  position: relative;
  width: 100vw;
  overflow-x: hidden;
}

ul {
  position:relative;
  left: 0;
  width: 330vw;
  height:100vh;
  animation-name: sliding0;
  animation-duration: 3s;
  animation-delay: 0s;
  animation-iteration-count: 1;
  animation-timing-function: linear;
  margin: 0;
  padding: 0;
  list-style-type: none;
}

li {
  position: relative;
  left:0;
  top:0;
  float:left;
  width: 32vw;
  height:30vw;
  display: inline-block;
  margin: 0;
  margin-right: 1vw;
  padding: 0;
  background-size: cover;
  background-repeat: no-repeat no-repeat;
  background-position: center center;
}

</style>
</head>
<body>
<script>

// we put the two lots of text and the image url for each slide in an array in the order they are to be shown
// this makes it easier to maintain when you want to add or remove a slide or change their order
// we only have one slider at the moment but this makes it more general

// these are the offsets in the array describing a slide. Done as indexes rather than named as easier to set up sliders array
const img = 0;
const text1 = 1;
const text2 = 2;

const sliders = [
  [
    [https://ahweb.org.uk/boxfordmosaic.jpg,Shire,Valley<br> of Dreams],
    [https://ahweb.org.uk/gear-in-turbine-house-reading.jpg,Westwood,Misty Woodlands],
    [https://ahweb.org.uk/tricycle-in-abbey-ruins.jpg,Shire,Valley<br> of Dreams],
    [https://ahweb.org.uk/boxfordmosaic.jpg,Shire,Valley<br> of Dreams],
    [https://ahweb.org.uk/gear-in-turbine-house-reading.jpg,Westwood,Misty Woodlands],
    [https://ahweb.org.uk/tricycle-in-abbey-ruins.jpg,Shire,Valley<br> of Dreams],
    [https://ahweb.org.uk/boxfordmosaic.jpg,Shire,Valley<br> of Dreams],
    [https://ahweb.org.uk/gear-in-turbine-house-reading.jpg,Westwood,Misty Woodlands],
    [https://ahweb.org.uk/tricycle-in-abbey-ruins.jpg,Shire,Valley<br> of Dreams],
    [https://ahweb.org.uk/tricycle-in-abbey-ruins.jpg,Shire,Valley<br> of Dreams]
  ]
];

// go through each slider and create its outer divs and its ul element
sliders.forEach(createSlider);

function createSlider(slider,sliderno) {
  const div1 = document.createElement(DIV);
  const div2 = document.createElement(DIV);
  const ul = document.createElement(UL);

  div1.classList.add(glide,hero-carousel);
  div2.classList.add(glide_track);
  div2.setAttribute(data-glide-el,track);

  div1.appendChild(div2);
  div2.appendChild(ul);
  document.body.appendChild(div1);

  ul.classList.add(glide__slides);
    
  ul.addEventListener(animationend, animationEnd);
 
  slider.forEach(createLi);

  function createLi(slide,slideNo) {
    const li = document.createElement(LI);
    li.classList.add(glide__slide,carousel-item);
    li.style.backgroundImage=url(+slide[img]+);
    li.addEventListener(click,slideClicked);
    li.addEventListener(mouseover,slideHovered);
    li.addEventListener(mouseout,slideUnhovered);
    
    li.setAttribute(data-slideno,0 + slideNo);//! needs generalising if you have >10 slides !

    ul.appendChild(li);

    const div = document.createElement(DIV);
    const p = document.createElement(P);
    const h3 = document.createElement(H3);

    p.innerHTML = slide[text1];
    div.appendChild(p);
    h3.innerHTML = slide[text2];
    div.appendChild(h3);

    li.appendChild(div);
  }
}

// this is for testing, in real version use whatever required (i.e. whichever element is to have the hero image)
function ahHeroChange(backgroundImage) {  
  document.body.style.background = backgroundImage +  bottom/cover no-repeat;
}

function slideClicked(event) {
  var slide = event.target;
  var slideNo = slide.getAttribute(data-slideno);
  
  // make the hero image the same as the slides
  ahHeroChange(slide.style.backgroundImage);
  
/* I dont know what these functions do - they were executed in the original on a click 

  number(slideno);
  h4(slide.firstElementChild.querySelector(p).innerHTML);// text1 of the slide is passed to h4
  h1(slide.firstElementChild.querySelector(h3).innerHTML;// text2 of the slide is passed to h1

*/
}

function slideHovered(event) {
  var slide = event.target;
  var slider = slide.parentElement;
  slider.style.animationPlayState = paused;
  ahHeroChange(slide.style.backgroundImage);
}

function slideUnhovered(event) {
  var slide = event.target;
  var slider = slide.parentElement;
  
  //restore the hero image to the first one in the slider
  ahHeroChange(slider.firstElementChild.style.backgroundImage);
  
  //get the animation running again
  slider.style.animationPlayState = running; 
}

function animationEnd(event) {
   //find the element that was clicked (it will be a ul element representing a slider)
   var slider = event.target;
   
  //take the first slide off the list and put it back at the end
  slider.append(this.firstElementChild);
  
  //change the hero image to the slide which is now the leftmost - use modified heroChange in the final version
  document.body.style.backgroundImage = this.firstElementChild.style.backgroundImage;
  
  // toggle the animationName (to an identical keyframes action) to force the animation to start again
  slider.style.animationName=sliding+(Number(event.animationName.replace(sliding,))+1)%2;
}

</script>
</body>
</html>

javascript – How to make autosliding carousel thumbnail change background image when active

Leave a Reply

Your email address will not be published.