javascript - jQuery:将 setIntervals 分配给数组时出现问题

标签 javascript jquery html jquery-selectors

我试图在一个页面上运行多个动画(某种幻灯片),但代码仅适用于实际存在的(在我的情况下)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);
        }
     }
});

通过测试,我已经证明循环运行成功,并将适当的目标和持续时间传递给 fad​​eSwitch 或 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')运行。即使通过将 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,除了最后输入的目标之外,它从未成功运行其他任何内容。

非常感谢任何建议或帮助。 谢谢。

最佳答案

当您调用 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>

关于javascript - jQuery:将 setIntervals 分配给数组时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5804924/

相关文章:

javascript - 当我回来时Ajax数据消失了

android - 如何更改本地 HTML 文件的装饰以在 Android 的 WebView 上显示它

Javascript 返回页面加载

javascript - 有没有办法将javascript结果打印到调用javascript函数的div中?

javascript - jade 中无法解释的 "<"和双输出包括

javascript - 如何使用 JavaScript (GTM) 从字符串中删除电子邮件

javascript - 为什么在 jQuery 中切换可拖动性的正确方法是?

jquery - $(window).height() 返回错误值

javascript - 如何使用javascript从左向右移动一个div

html - 我有一个容器流体,它没有扩展到整个屏幕,即使它应该是