2015-08-02 2 views
4

У меня есть список элементов для анимации с помощью CSS3, например, так:только каждый второй элемент повторяется

.anim-slide-left { 
    animation: anim-slide-left 0.8s ease forwards; 
    -webkit-animation: anim-slide-left 0.8s ease forwards; 

} 
@-webkit-keyframes anim-slide-left { 
    0% { 
     transform: translateX(-500px); 
     -webkit-transform: translateX(-500px); 
     opacity: 0; 
    } 
    100% { 
     transform: translateX(0); 
     -webkit-transform: translateX(0); 
     opacity: 1; 
    } 
} 

/* there are more, but very similar */ 

При загрузке страницы JS должны анимировать только видимые элементы с помощью специальных классов «живой»:

$(function() { 

    var $window = $(window); 
    var $toAnimate = $('.animate'); 
    animate(); 

     // check if element is on the viewport 
    function isElementVisible(elementToBeChecked) 
    { 
     var TopView = $(window).scrollTop(); 
     var BotView = TopView + $(window).height(); 
     var TopElement = elementToBeChecked.offset().top; 
     return ((TopElement <= BotView) && (TopElement >= TopView)); 
    } 
     // add css animation class 
    function animate() 
    { 
     $toAnimate.each(function(i, el) 
     { 
      var $el = $toAnimate.eq(i); 

      if ($el.length && isElementVisible($el)) 
      { 
        // remove already visible elements 
       $toAnimate.splice(i, 1); 

        // setting up animation effect 
       $el.addClass($el.data('effect')); 

       $el.removeClass('animate'); 
      } 
     }); 
    } 
}); 

Теперь вот в чем проблема. Только каждый второй элемент проверяется, как видно, например, так:

enter image description here

Но это должно быть так:

enter image description here

Остальные элементы оживляются только тогда, когда страница прокручивается вниз , с:

$window.scroll(function() 
{ 
    animate(); 
}); 

Как проходить через каждый элемент в этом сценарии?

EDIT:

принимая во внимание @ T.J. Crowder комментарии я изменил функцию анимации с функцией фильтра, предложенной @charlietfl:

$('.animate').filter(function(idx) { 
    if(isElementVisible($(this))) 
    { 
     $(this).addClass($(this).data('effect')); 
     $(this).removeClass('animate'); 
    } 
}); 

Он работает просто отлично :) Спасибо вам, ребята.

+4

Ну, такие вещи, как, что, вероятно, произойдет при удалении записей из набора вы зацикливаете ('$ toAnimate'). –

+0

Также обратите внимание, что 'splice' не является официальным методом jQuery. Это недокументировано и может исчезнуть в любое время. (Объекты jQuery не являются массивами, они просто * похожими на массив *.) –

+0

** И ** насколько мне известно, jQuery делает [никаких гарантий] (http://api.jquery.com/each/) о том, что «каждый» будет делать, если вы добавите или удалите записи в наборе, который вы повторяете (в отличие от JavaScript 'forEach'). –

ответ

5

Несколько проблем нет:

  1. Вы модифицирование набора ($toAnimate), что вы итерацию, и вы извлечение элементов из этого набора с постоянно увеличивающимся индексом. Естественно, если вы удалите один, с этого момента ваши индексы будут отключены.

  2. splice не является официальным методом jQuery. Это недокументировано и может исчезнуть в любое время. (Объекты JQuery не являются массивами;. Они просто массива как)

  3. Насколько я знаю, JQuery делает no guarantees о том, что each будет делать, если добавить или удалить записи в наборе вы находитесь итерация (в отличие от JavaScript forEach).

Потому что у вас есть splice и итерационная гарантия от forEach, вы могли бы сделать $toAnimate фактический массив с помощью .get:

var $toAnimate = $('.animate').get(); 
// ---------------------------^^^^^^ 

... а потом:

function animate() 
{ 
    $toAnimate.forEach(function(el) 
    { 
     var $el = $(el); 
     if (isElementVisible($el)) 
     { 
      // remove already visible elements 
      $toAnimate.splice(i, 1); 

      // setting up animation effect 
      if($el.data('effect') == 'anim-bar') animateBar($el); 
      else $el.addClass($el.data('effect')); 

      $el.removeClass('animate'); 
     } 
    }); 
} 
1

Вы удаляют элементы из массива, который вы итерируете, поэтому следующий элемент заменит текущий. Когда вы переходите к следующему элементу, это пропускает один элемент.

Если вы Переберите массив с конца, удаление элементов не влияет на детали позже в цикле:

function animate() 
{ 
    for (var i = $toAnimate.length - 1; i >= 0; i--) 
    { 
     var $el = $toAnimate.eq(i); 

     if ($el.length && isElementVisible($el)) 
     { 
       // remove already visible elements 
      $toAnimate.splice(i, 1); 

       // setting up animation effect 
      if($el.data('effect') == 'anim-bar') animateBar($el); 
      else $el.addClass($el.data('effect')); 

      $el.removeClass('animate'); 
     } 
    }); 
} 
+0

Это работает, спасибо, но я должен также обратить внимание на другие комментарии, такие как совместимость jquery. – goldjunge