问题
I am trying to build a slideshow using the jQuery Cycle plugin that contains another level of nested slideshows within some of the top-level slides.
The main "container" slides slide horizontally, and then—for "container" slides that contain more than one image on the left-hand side—those images slide up vertically.
Sample here, because I imagine it's hard to visualize: http://dl.dropbox.com/u/2890872/js-test/index.html
You'll only get to the second top-level slide before it stops, even thought there are six top-level slides (which is my issue—the second slide only contains one left-hand inner image, which stops the script), but you can see what the intended transitions are and check out the entire code.
The problem is that not all of the secondary slideshows have more than one image, and jQuery Cycle terminates itself if there is one or less images in a slideshow. This termination also terminates the top-level slideshow, since it is stopped and started based on when the secondary slideshow ends. Since the secondary slideshow terminates due to only one "slide", then the next outer top-level slide never gets called. I'm not sure how to adapt the code to get around this.
The js:
<script type="text/javascript">
$(function(){
// init and stop the inner slideshows
var inners = $('.slide-up').cycle().cycle('stop');
var slideshow = $('#home-slides').cycle({
fx: 'scrollHorz',
speed: 300,
timeout: 0,
before: function() {
// stop all inner slideshows
inners.cycle('stop');
// start the new slide's slideshow
$(this).children().cycle({
fx: 'scrollUp',
timeout: 2000,
autostop: true,
end: function() {
// when inner slideshow ends, advance the outer slideshow
slideshow.cycle('next');
}
});
}
});
});
</script>
A sample of the html:
<div id="home-slides">
<div>
<div class="slide-up">
<img src="i/home/slideshow/1l-1.jpg" alt="" width="284" height="420" />
<img src="i/home/slideshow/1l-2.jpg" alt="" width="284" height="420" />
<img src="i/home/slideshow/1l-3.jpg" alt="" width="284" height="420" />
</div>
<img src="i/home/slideshow/1r.png" alt="" width="291" height="420" />
</div>
<div>
<div>
<img src="i/home/slideshow/2l-1.jpg" alt="" width="284" height="420" />
</div>
<img src="i/home/slideshow/2r.jpg" alt="" width="291" height="420" />
</div>
<div>
<div class="slide-up">
<img src="i/home/slideshow/3l-1.jpg" alt="" width="284" height="420" />
<img src="i/home/slideshow/3l-2.jpg" alt="" width="284" height="420" />
</div>
<img src="i/home/slideshow/3r.png" alt="" width="291" height="420" />
</div>
<div>
…additional slides…
</div>
</div>
The slideshow terminates at the second #home-slides > div because there is only one image. I've tried removing the nesting and the "slide-up" class from the slides with no inner-slideshow, but that doesn't help.
Again, full working version with all relevant code can be found here: http://dl.dropbox.com/u/2890872/js-test/index.html
----------- EDITED 4/10 - Minor Updates and possibly a lead ----------
I've edited the code here and on the example link just to add some details that elmininate the first thoughts for troubleshooting. Now, only the the slides with secondary slideshows use the class "slide-up".
- I've tried specifying the '.slide-up' class in the function for the "end" callback ('$(this).children('.slide-up').cycle
…'), which does prevent cycle from terminating for too few slides, but that only makes it terminate for unmatched elements!
The closest I've gotten is by adding a conditional check to the function in the end callback: (I'm using length to check the existence of a slide-up div. If there's a better way, let me know)
before: function() {
if ( $(this).children('.slide-up').length != 0 ) {
// stop all inner slideshows
inners.cycle('stop');
// start the new slide's slideshow
$(this).children('.slide-up').cycle({
fx: 'scrollUp',
timeout: 2000,
autostop: true,
end: function() {
// when inner slideshow ends, advance the outer slideshow
slideshow.cycle('next');
}
});
} else alert('NO INNER SLIDESHOW!');
This eliminates all errors and terminations directly from jQuery Cycle, but the main slideshow still stops at the slide without a secondary slideshow. I think need to put something in the "else" statement related to firing up "slideshow.cycle('next');", but I haven't figured out the proper syntax to get that to work.
----------- EDIT #2 4/10 - ----------
most recent working example: http://dl.dropbox.com/u/2890872/js-test/index2.html
Moving the before function into its own named function to keep things cleaner.
function onBefore(currSlideElement, nextSlideElement, options, forwardFlag) {
if ( $(this).children('.slide-up').length != 0 ) {
// stop all inner slideshows
//inners.cycle('stop');
// start the new slide's slideshow
$(this).children('.slide-up').cycle({
fx: 'scrollUp',
timeout: 2000,
autostop: true,
end: function() {
// when inner slideshow ends, advance the outer slideshow
slideshow.cycle('next');
}
});
}
// else null;
else $(this).parent().cycle({
end: function() { slideshow.cycle('next'); }
});
}
This (else statement) allows the slideshow to progress, but it doesn't preserve the original 'slideshow' options, and just starts playing the top-level slides with default out-of-the-box options (fades from one slide to the next, instead of sliding, stops playing secondary slides).
I don't understand: 1) How to preserve the options. (I thought that was why the var "slideshow" was created in the first place)
2) Why an else statement is even necessary—I don't understand why the outer slides are stopping at all when the conditional '.slide-up' statement isn't executed— I would think the outer slideshow would just continue as normal.
回答1:
A facebook friend solved it! Thanks, facebook friend!
var slideshow = $('#home-slides').cycle({
fx: 'scrollHorz',
speed: 300,
timeout: 0,
before: function(curElement, nextElement, options, forwardFlag) {
if($(nextElement).children('.slide-up').length != 0) {
$(nextElement).children('.slide-up').cycle({
fx: 'scrollUp',
timeout: 2000,
autostop: true,
end: function() { slideshow.cycle('next'); }
});
}
else {
setTimeout(function(){ slideshow.cycle('next'); }, 2000);
}
}
});
Working example here: http://dl.dropbox.com/u/2890872/js-test/index3.html I need to study Cycle a bit more and the changes he's made to fully understand the role of 'nextElement' in this code, but it most certainly works!
回答2:
Check if this approach helps you: http://www.devcha.com/2010/05/fixed-cycle-terminating-too-few-slides.html
Did you check this question...looks similar problem, but different approach: Nested jQuery Cycle?
回答3:
After I "awarded" the cycle plugin as the best and simpliest slideshow plugin ever, I put some eyes more on it, and did some experiments and spent some hours with it. Results: 1. the cycle().cycle('stop') as same as just cycle('stop') never worked properly, it stops the inner slideshows after every 2nd content. I changed it into a single cycle({timeout:0})... which I do not really understand, but it works absolutely fine, including firebug reviews on js activity. 2. As I needed it to be working on more than just one usage per page, and the aibility to auto-decision, if controls are needed or not, so I changed a couple of things and put the entire js in the $(document).ready(function() {} in the header of the page. The first .inner-slideshow gets an added class="active" from serverside php script.
The code now looks like that
//-----------------jquery cycle plugin modified by Michael Gerner, ddlab, 2012-01-15---------------
$('.slideshow').each(function(){
var sl = $(this);
var sl_index = sl.index('.slideshow');
var allinner = sl.find('.inner-slideshow');
var firstinner = sl.children('.inner-slideshow:eq(0)');
//----settings outer slideshow
var outerfx = 'scrollHorz';
var outerspeed = 500;
var outertimeout = 0;
var outerprev = '#sl'+sl_index+'prev';
var outernext = '#sl'+sl_index+'next';
//----settings inner slideshow
var innerfx = 'fade';
var innerspeed = 2000;
var innertimeout = 6000;
if (allinner.size() > 1) { //---------more than one inner slideshow
var setcontrols = '<div class="slideshow-controls"><a class="prev" id="sl'+sl_index+'prev" href="#"></a> <a class="next" id="sl'+sl_index+'next" href="#"></a></div>';
sl.after(setcontrols);
var controls_a = sl.find('.slideshow-controls a');
controls_a.click(function(){
var activeinners = sl.find('.active');
activeinners.each(function(){
$(this).removeClass('active').cycle({timeout:0});
});
});
sl.cycle({
fx:outerfx,
speed:outerspeed,
timeout:outertimeout,
prev:outerprev,
next:outernext,
before:function(){
var activeinners = sl.find('.active');
activeinners.each(function(){
$(this).removeClass('active').cycle({timeout:0});
});
},
after:function(){
$(this).addClass('active').cycle({
fx:innerfx,
speed:innerspeed,
timeout:innertimeout,
autostop: true,
end: function() { sl.cycle('next'); }
});
}
});
}
else { //------------just one inner slideshow
firstinner.cycle({
fx:innerfx,
speed:innerspeed,
timeout:innertimeout
});
}
});
//-----------------jquery cycle plugin modified by Michael Gerner, ddlab, 2012-01-15---------------
Now I am happy with it, specially the browserload on js activity is extremely small, which I want to point out as important for mobile devices, and finally I added some frontend-editing tools, such as html5upload and a jq-filemanager, which is used for the owner of the website to manage the content for the gallery.
Thanks for all previous reviews and tuts, that helped me a lot to get this track :-) You may find a lightweight screenshot image (26kb) on here http://ddlab.de/screenshots/cycle_gallery.jpg
回答4:
I uploaded the working example here http://ferienhaus-fischland-ahrenshoop.de/mini4/ After finishing this project in the near future, you´ll find the gallery anywhere on this page http://ferienhaus-fischland-ahrenshoop.de probably on the start page and others.
来源:https://stackoverflow.com/questions/5607514/jquery-cycle-multiple-nested-slideshows-and-cycle-terminating