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

发布于 2024-11-03 18:43:13 字数 2915 浏览 0 评论 0 原文

我试图在一页上运行多个动画(某种幻灯片),但代码仅适用于实际存在的(在我的情况下)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,并且除了最后输入的目标之外,它从未成功运行其他任何内容。

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

I'm attempting to run multiple animations (slideshows of sorts) on one page, but the code is only working for one of the (in my case) 3 slideshows that are actually present.

The issue is not with the animation but with the actual initialisation and running of functions (explained better below by looking at the code):

The 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);
        }
     }
});

Through testing, I have shown that the loop runs successfully and passes the appropriate target and duration to either fadeSwitch or slideSwitch for all 3 runs of the loop.

fadeSwitch and slideSwitch are identical except for the animation part, for example:

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');
});
}

However this function will run only using the last found target (i.e t = '.someClass3'). Even though by placing console.log alerts in the setInterval functions I know that it is applying the correct variables.

e.g.

plays[0] = setInterval(function(){fadeSwitch('.someclass1');}, 8500);
plays[1] = setInterval(function(){fadeSwitch('.someclass2');}, 4000);
plays[2] = setInterval(function(){fadeSwitch('.someclass3');}, 5000);

Yet as I have tried to (badly) explain, if I place a console.log inside of fadeSwitch to test what is being passed as the target when it runs (remember it is set to run after an interval, so by the time the .someClass1 function runs for the first time, the plays[] array is full and finished) the log shows that the target is always .someClass3 and it never succesfully runs for anything else but that last entered target.

Any suggestions or help is greatly appreciated.
Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

匿名的好友 2024-11-10 18:43:13

当您调用 setInterval 时,t 的值将被匿名函数“封闭”。对于循环的每次迭代,您都会创建一个新的匿名函数,并且就像您所说的那样,此时 t 具有正确的值。

问题是,当每个函数执行时,t 的值已经改变(它将保存循环的最后一个值),并且所有三个匿名函数都引用同一个 t 变量(即闭包的性质和 javascript 的词法范围)。快速解决方法是为每个匿名函数提供正确的,而不是对 t 的引用:

将 this: 更改

plays[x] = setInterval(function(){fadeSwitch(t);}, duration);

为 this:

plays[x] = setInterval((function(t2){ return function(){ fadeSwitch(t2); }; })(t), duration);

显然,对于与 slideSwitch 相同的行,这是相同的。

我觉得我应该指出的另一件事是:您在 html 中使用了无效属性,请考虑寻找替代方案,例如隐藏的嵌入标记(例如

),或类名,或html5数据属性,而不是

The value of t is being "closed over" by your anonymous functions when you call setInterval. For every iteration of your loop you create a new anonymous function, and like you said, at the time t 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:

plays[x] = setInterval(function(){fadeSwitch(t);}, duration);

to this:

plays[x] = setInterval((function(t2){ return function(){ fadeSwitch(t2); }; })(t), duration);

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>

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文