Looped jQuery slideshow with smooth cross-fades
I'm trying to do a simple rotating image on the home page. Under the hood I'm reading a directory and then populating urls for the images into an array. What I want to do is cross-fade the images. If it was just a matter of showing the next one, it's easy, but since I need to cross-fade, it's a bit harder. I think what I want to do is do the fades by calling animate()
on the opacity
value of the <img>
tag, and in between swapping out the css background-image
property of the enclosing <div>
. But the results are not that great.
I've used tools for more full featured slideshows, but I don't want the overhead of adding a plugin if I can avoid it, and a simple crossfade seems like it should be easier.
Here's my JavaScript (I'm using jQuery 1.3.2):
var slideshow_images = ["http:\/\/example.com\/wordpress\/wp-content\/themes\/testtheme\/sidebar-home-bg\/bg1.jpg","http:\/\/example.com\/wordpress\/wp-content\/themes\/testtheme\/sidebar-home-bg\/bg2.jpg","http:\/\/example.com\/wordpress\/wp-content\/themes\/testtheme\/sidebar-home-bg\/bg3.jpg"];
var slideshow_index = 0;
var delay = 4000;
var swapSlides = function() {
var slideshow_count = slideshow_images.length;
// initialize the background to be the current image
$('#home-slideshow').css({
'background-image': 'url(' + sl开发者_运维知识库ideshow_images[slideshow_index] + ')',
'background-repeat:': 'no-repeat',
'width': 200,
'overflow': 'hidden'
});
slideshow_index = ((slideshow_index + 1) == slideshow_count) ? 0 : slideshow_index + 1;
// fade out the img
$('#home-slideshow img').animate({opacity: 0}, delay);
// now, the background is visible
// next change the url on the img
$('#home-slideshow img').attr('src', slideshow_images[slideshow_index]);
// and fade it up
$('#home-slideshow img').animate({opacity: 1.0}, delay);
// do it again
setTimeout('swapSlides()', 4000);
}
jQuery(document).ready(function(){
if (swapSlides) {
swapSlides();
}
});
And here's the markup I'm using:
<div id="home-slideshow"><img src="http://example.com/wordpress/wp-content/themes/testtheme/sidebar-home-bg/bg1.jpg" alt="" /></div>
The first thing that you should be aware of and that must be causing problems with your code : the animate methods are not synchronous ! So when you do :
$('#home-slideshow img').animate({opacity: 0}, delay);
// now, the background is visible
// next change the url on the img
$('#home-slideshow img').attr('src', slideshow_images[slideshow_index]);
You start to animate, but the method immediately returns. You can imagine the animation as a background thread , although there is no such thing as a thread in JavaScript and everything is implemented using settimeout calls.
So in your code, at the moment you change the src attribute, the image is probably still 99% visible. And then you start to animate it back to 100% opacity, but at this point it is still at say 98%, and the two "threads" will try to simultaneously make it appear/disappear !
So in your code will need to either set timeouts to execute the tasks in the correct order (always leaving a few milliseconds of margin inbetween), or, safer but maybe less readable when you have many successive function calls, use the callback function of the animate method. For example :
$('#home-slideshow img').animate({opacity: 0}, delay, function(){
// now, the background is visible
// next change the url on the img
$('#home-slideshow img').attr('src', slideshow_images[slideshow_index]);
// and fade it up
$('#home-slideshow img').animate({opacity: 1.0}, delay, function(){
// do it again
setTimeout('swapSlides()', 4000);
});
});
Finally, what you are doing is a fade-out + fade in. If you want a real cross fade you'll need to have 2 element simultaneously at some point :
- start : there is only one element, with opacity 100%
- build your new element with the right url for the background image (or use an img element)
- add the new element to the dom tree with opacity 0%, as a sibling to the existing one
- start to animate simultaneously the opacity of the current element from 100% to 0% and the opacity of the new element from 0% to 100%
- remove the old, now invisible element
try this:
DEMO: http://jsbin.com/ipudo/7
few line of jQuery
$(function(){
$('#home-slideshow img:gt(0)').hide();
setInterval(function(){
$('#home-slideshow :first-child').fadeOut()
.next('img').fadeIn()
.end().appendTo('#home-slideshow');},
3000);
});
2 line of CSS
#home-slideshow { position:relative; height:332px; width:500px; }
#home-slideshow img { position:absolute; left:0; top:0; }
your HTML
<div id="home-slideshow">
<img src="image.jpg" alt=""/>
<img src="image.jpg" alt=""/>
<img src="image.jpg" alt=""/>
...
...
</div>
精彩评论