best websites of the world

The Simplest of Slideshows

Sunday, August 11, 2013

I've been doing a lot of design work recently, and with that practicing my jQuery skills. One of the most popular elements on a webpage these days is the slideshow. It goes along with the idea that people are reading less and would rather get the information from a picture. However, many of the tutorials for slideshows either lack functionality or are too complex. This is how I solved the problem.

The first thing to setup is all the HTML and CSS for it. I've created an unordered list with a specific id and list items within it. With CSS, I've cleared the default style of the unordered list and positioned the list items absolutely, so they end up on top of each other. There are obviously several different ways of setting this sort of thing up with CSS so it didn't matter much how I went about testing it.

So, the next step was to show one list item at a time on every time a link was clicked. The way I did this was by setting one list item at a time to a new class called "active". So the first list item would be given the class active when the page is loaded.

$(window).load(function(){
$('ul#slideshow li:first-child').addClass("active");
});

When I click the link, the code will find the active list item, remove the active class from it, find the next list item and assign the active class to it. Like this:

$('ul#slideshow li.active').removeClass("active").next().addClass("active");

Of course there's a problem when I reach the end of the list, since I run out of list items. What you want to do is make a conditional statement that finds out when you reach the end of the list. One example is to say: "if the active class list item is the same as the last list item, then go to the first item next". The way I did it is a little different:

if($('ul#slideshow li').length != $('ul#slideshow li.active').index() + 1){}

This code says, if the number of list items does not equal the location of the current active class list item then do the thing in the curly brackets. The reason the plus one is at the end is because the index code starts at zero, so if I have four list items the last one would be at position three. The thing in the curly brackets is the class moving code from before. The full function for moving to the next list item is this:

function moveRight(){
if($('ul#slideshow li').length != $('ul#slideshow li.active').index() + 1){
$('ul#slideshow li.active').removeClass("active").next().addClass("active");
}
else{
$('ul#slideshow li.active').removeClass("active");
$('ul#slideshow li:first-child').addClass("active");
}
};

Moving to the left is similar except when we get to the first list item (or index 0) then we want to move the last item:

function moveLeft(){
if($('ul#slideshow li.active').index() != 0){
$('ul#slideshow li.active').removeClass("active").prev().addClass("active");
}
else{
$('ul#slideshow li.active').removeClass("active");
$('ul#slideshow li:last-child').addClass("active");
};
};

So now that we've assigned at active class to the list item that is showing, we can style the list item differently from the other list items. You can make all the other list items transparent and then the active list item opaque. You can also add keyframe animations to the active list item and they will play once the active class is assigned to the list item.

However, we're not done yet. The next part was the hardest to figure out and I didn't see much in the way of answers online. What I wanted to do next is have the slideshow autoplay until the link was clicked to go to the next slide. Then (and here's the hard part), I want to restart the autoplay after a few seconds. One of the first things that may come to mind is using the setInterval command and making it play the moveRight function every so many seconds and then use clearInterval to stop the autoplay, and then setInterval again after a delay. There's a huge problem with this because if I click the moveRight link several times, the setInterval function seems to stock up on commands and you'll see the player jump instead of fire at regular intervals.

Some places on the internet were talking about using setTimeout instead of setInterval but I didn't understand how I was supposed to replace it until I found that you can call a function from inside itself, basically making the function repeat. Let me show you the code and then I can explain a bit better:

var delay = 3000;
var time;

function startLoop(){
time = setTimeout(function(){
startLoop();
moveRight();
}, delay)
delay = 3000;
};

So, here's what is happening; I set two global variables outside the function to store information. I'll skip delay for now although it should be understandable what that is for. The "time" variable is outside so that I can clear the timer from another function. If I set the variable inside the startLoop function, I wouldn't be able to get to it to turn it off. Then we make the startLoop function which will start a timer for another unnamed function. The unnamed function will fire the startLoop function (the parent function, if you will) and the moveRight function after the delay. Then I set the delay to 3000 milliseconds (3 seconds). Now, here's where the magic happens. After 3 seconds, then the startLoop function will fire again (as per the timer we set when we first fired it). It will then do all of those steps again; setting the timer, moving to the right and then setting the delay for the timer. Just remember to start the loop when the page is ready.

$(document).ready(startLoop);

The next piece of the puzzle is to pause the loop when I click to go to the next slide. To do that, I'll want to clear the timer and then start the timer with a longer delay. This explains why the delay variable is also outside of the function, so I can set a new value to it when I click to the next slide. Like this:

$('a.right').click(function(){
moveRight();
clearTimeout(time);
delay = 6000;
startLoop();
});

Clicking left is the same as right except for firing the moveLeft function instead. You can also see why I put the 3 second delay at the end of the startLoop function, so that it will reset the timer for the loop after the longer delay is finished. The last thing I wanted to do is to pause the autoplay when the mouse is over the slideshow. This is pretty easy using what I have so far, you just split the click function into a section for when the mouse goes in (clear the timer and set a new delay) and when the mouse leaves (start the loop).

$('ul#slideshow').mouseover(function(){
clearTimeout(time);
delay = 6000;
});
$('ul#slideshow').mouseout(function(){
startLoop();
});

That's basically it. Like I said in the beginning of this post, it has all the functionality of many of the slideshows seen around the internet (autoplay, controls, pause on hover) without plugins (other than jQuery) or mountains of hard to figure out code.

No comments: