我正在尝试在一个页面上运行多个动画(各种幻灯片),但代码仅适用于其中一个(在我的情况下)实际存在的3个幻灯片。
问题不在于动画,而在于实际初始化和运行功能(下面通过查看代码解释得更好):
HTML:
<div class="someclass1" rel="slideshow" type="fade" duration=8500>
<div class="wrapper">...</div>
<div class="wrapper">...</div>
</div>
<div class="someclass2" rel="slideshow" type="slide" duration=4000>
<div class="wrapper">...</div>
<div class="wrapper">...</div>
</div>
<div class="someclass3" rel="slideshow" type="fade" duration=5000>
<div class="wrapper">...</div>
<div class="wrapper">...</div>
</div>
jQuery的:
$(function() {
var plays = [];
var duration = 0;
var targets = [];
var t = "";
var $obs = $('div[rel="slideshow"]')
for(var x = 0; x < $obs.length; x++){
$obs.eq(x).children('.wrapper').eq(0).addClass('active');
$obs.eq(x).children('.wrapper').css({opacity: 0.0});
$obs.eq(x).children('.active').css({opacity: 1.0});
$obs.eq(x).children('.navigation a.slide-buttons').eq(0).addClass('current');
// Set duration
duration = $obs.eq(x).attr('duration');
// Set target
targets = $obs.eq(x).attr('class').split(' ');
t = '';
for(var i=0; i<targets.length; i++){
t += '.' + targets[i];
}
if($obs.eq(x).attr('type')==='fade'){
plays[x] = setInterval(function(){fadeSwitch(t);}, duration);
}
else if($obs.eq(x).attr('type')==='slide'){
plays[x] = setInterval(function(){slideSwitch(t);}, duration);
}
}
});
通过测试,我已经证明循环成功运行并将适当的目标和持续时间传递给fadeSwitch或slideSwitch,用于循环的所有3次运行。
除了动画部分之外,fadeSwitch和slideSwitch是相同的,例如:
function fadeSwitch(target) {
var $active = $(target+' .active');
if ( $active.length === 0 ){ $active = $(target+' .wrapper:first');}
var $next = $active.next('.wrapper').length ? $active.next('.wrapper')
: $(target+' .wrapper:first');
// FADE ANIMATIONS
$active.animate({opacity : 0.0}, 500, function() {
$active.addClass('last-active');
});
$next.animate({opacity: 1.0}, 500, function() {
$active.removeClass('active last-active');
$next.addClass('active');
});
}
但是,此函数仅使用最后找到的目标运行(即t ='。someClass3')。即使通过在setInterval函数中放置console.log警报,我也知道它正在应用正确的变量。
e.g。
plays[0] = setInterval(function(){fadeSwitch('.someclass1');}, 8500);
plays[1] = setInterval(function(){fadeSwitch('.someclass2');}, 4000);
plays[2] = setInterval(function(){fadeSwitch('.someclass3');}, 5000);
然而,正如我试图(严重)解释的那样,如果我在fadeSwitch中放置一个console.log来测试它在运行时作为目标传递的内容(记住它设置为在一个间隔后运行,所以由时间.someClass1函数第一次运行,plays []数组已满且已完成)日志显示目标始终为.someClass3,除了最后输入的目标之外,它永远不会成功运行。
非常感谢任何建议或帮助。 谢谢。
答案 0 :(得分:3)
当您致电t
时,您的匿名函数正在“关闭”setInterval
的值。对于循环的每次迭代,您都会创建一个新的匿名函数,就像您说的那样,t
具有正确的值。
问题在于,每个函数执行时t
的值已经改变(它将保存循环的最后一个值),并且所有三个匿名函数都引用相同的t变量(即闭包的本质和javascript的词法范围)。快速解决方法是为每个匿名函数提供正确的值,而不是对t的引用:
改变这个:
plays[x] = setInterval(function(){fadeSwitch(t);}, duration);
到此:
plays[x] = setInterval((function(t2){ return function(){ fadeSwitch(t2); }; })(t), duration);
与slideSwitch
相同的行显然相同。
我觉得我应该指出的另一件事是:你在你的html中使用了无效属性,考虑找一个替代方法,比如隐藏的嵌入式标记(例如<div class="duration" style="display:none">5000</div>
),或者类名,或html5数据属性,而不是<div duration=5000>