jQuery:将 setIntervals 分配给数组时出现问题
我试图在一页上运行多个动画(某种幻灯片),但代码仅适用于实际存在的(在我的情况下)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);
}
}
});
通过测试,我已经表明循环成功运行并传递了适当的目标和持续时间对于循环的所有 3 次运行,选择 fadeSwitch 或 slipSwitch。
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')运行。尽管通过将 console.log 警报放置在 setInterval 函数中,我知道它正在应用正确的变量。
例如,
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,并且除了最后输入的目标之外,它从未成功运行其他任何内容。
非常感谢任何建议或帮助。 谢谢。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
当您调用
setInterval
时,t
的值将被匿名函数“封闭”。对于循环的每次迭代,您都会创建一个新的匿名函数,并且就像您所说的那样,此时t
具有正确的值。问题是,当每个函数执行时,
t
的值已经改变(它将保存循环的最后一个值),并且所有三个匿名函数都引用同一个 t 变量(即闭包的性质和 javascript 的词法范围)。快速解决方法是为每个匿名函数提供正确的值,而不是对 t 的引用:将 this: 更改
为 this:
显然,对于与
slideSwitch
相同的行,这是相同的。我觉得我应该指出的另一件事是:您在 html 中使用了无效属性,请考虑寻找替代方案,例如隐藏的嵌入标记(例如
),或类名,或html5数据属性,而不是
The value of
t
is being "closed over" by your anonymous functions when you callsetInterval
. For every iteration of your loop you create a new anonymous function, and like you said, at the timet
has the right value.The problem is that by the time each function executes
t
's value has changed (it will hold the last value of the loops), and all three anonymous functions refer to the same t variable (that is the nature of a closure and the lexical scoping of javascript). The quick fix is to give each anonymous function the right value and not a reference to t:Change this:
to this:
And obviously the same for the same line with
slideSwitch
.Another thing I felt I should point out: You're using invalid attributes in your html, consider finding an alternative, like hidden embedded markup (e.g.
<div class="duration" style="display:none">5000</div>
), or class names, or html5 data attributes, instead of<div duration=5000>