jQuery: проблема с назначением setIntervals к массиву - PullRequest
0 голосов
/ 27 апреля 2011

Я пытаюсь запустить несколько анимаций (своего рода слайд-шоу) на одной странице, но код работает только для одного из (в моем случае) 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'). Хотя, помещая предупреждения console.log в функции setInterval, я знаю, что он применяет правильные переменные.

, например

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

Тем не менее, как я пытался (плохо) объяснить, помещу ли я console.log в fadeSwitch для проверки того, что передается в качестве цели, когда он запускается (помните, что он настроен на запуск после интервала, поэтому Когда функция .someClass1 запускается в первый раз, массив plays [] заполнен и завершен) журнал показывает, что целью всегда является .someClass3, и он никогда не выполняется ни для чего другого, кроме последней введенной цели.

Любые предложения или помощь с благодарностью. Спасибо.

1 Ответ

3 голосов
/ 27 апреля 2011

Значение 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>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...