从嵌套动画

时间:2016-03-04 22:32:00

标签: javascript jquery animation

我有一个用于操纵单个字母的动画循环。它包含在计时器中以创建延迟偏移。每个字母的动画比前一个字母晚100毫秒。我需要弄清楚如何在完整动画完成时告诉我,但由于使用的嵌套类型不同,我遇到了一些麻烦。

我尝试了一些不同的东西,包括尝试从动画中返回一个值,然后是计时器,然后是$ .each函数,但我确定这是关闭的。我也在想我可以使用jQuery的animate函数提供的承诺,但不确定如何实现它。任何建议将不胜感激:]谢谢

这是我目前的代码:

var offset = 200;
//drop individual letters down out of view
    function dropLetters($letters){

        var len = $letters.length - 1;

        $letters.each(function(i){

            var $letter = $(this);

            setTimeout(function(){

                $letter.animate({ top: offset + 'px' }, 300, function(){
                    if( i >= len ){
                        return $(this).promise();
                    }
                });

            }, 100 * i );

        });

    }

编辑:对不起我意识到我省略了偏移量变量。我添加了这个 - 它只是设置为200.

另外,我意识到这个问题与另一个问题类似,但它似乎也与此不同。这里提供的答案给出了一些在另一个问题中不存在的不同方法。

4 个答案:

答案 0 :(得分:3)

利用.promise() $.when() Function.prototype.apply()$.map().delay()的方法。请注意,.apply().promise()替换为$.when()以返回this作为包含元素的jQuery对象,而不是包含.then()处的jQuery对象的数组

var offset = 100, duration = 300, delay = 100, curr = 0;

function dropLetters(elems) {
  return $.fn.promise.apply(elems, $.map(elems, function(el) {
    return $(el).delay(curr += delay).animate({top: offset + "px"}, duration)
  }))
}

dropLetters($("button")).then(function() {
  console.log("complete", this)
})
button {
  position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<button>
  0
</button>

<button>
  1
</button>

<button>
  2
</button>

或者,使用$.when().queue()

var offset = 100, duration = 300, delay = 100, curr = 0;

function dropLetters(elems) {
  return $.when(elems.queue(function (next) { 
    $(this).delay(curr += delay).animate({top:offset + "px"}, duration, next())}))
}

dropLetters($("button")).then(function() {
  console.log("complete", this)
})
button {
  position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<button>
  0
</button>

<button>
  1
</button>

<button>
  2
</button>

答案 1 :(得分:2)

您可以在每个setTimeout电话中做出承诺,并且您不需要自己跟踪所有异步操作已完成。

function dropLetters($letters){
  var promises = [];
  $letters.each(function(i){
    var $letter = $(this);
    promises.push(new Promise(function(resolve, reject) {
      setTimeout(function(){
        $letter.animate({ top: offset + 'px' }, 300, function(){
            resolve();
        });
      }, 100 * i );
    });               
  });
  return Promise.all(promises);
}

请注意,您可能需要Promise polyfill请参阅http://caniuse.com/#feat=promises

我对现有检查索引的答案的一个好处是,如果您将动画更改为向后,则必须在两个位置修改代码。请参阅下面的版本,其中字母向后(向前)飞出。

&#13;
&#13;
function dropLetters($letters, backwards) {
  var promises = [];
  $letters.each(function(i) {
    var $letter = $(this);
    promises.push(new Promise(function(resolve, reject) {
      setTimeout(function() {
        $letter.animate({
          top: '-100px'
        }, 300, function() {
          resolve();
        });
      }, 100 * (backwards ? $letters.length - i : i));
    }));
  });
  return Promise.all(promises);
}

dropLetters($('p')).then(function() {
  alert('finished')
});
  
dropLetters($('span'), true).then(function() {
  alert('finished')
});
&#13;
p, span {
  position: relative;
  float: left;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>
<p>A</p>

<hr style="clear: both"/>

<span>B</span>
<span>B</span>
<span>B</span>
<span>B</span>
<span>B</span>
<span>B</span>
<span>B</span>
<span>B</span>
<span>B</span>
<span>B</span>
<span>B</span>
<span>B</span>
<span>B</span>
<span>B</span>
<span>B</span>
<span>B</span>
&#13;
&#13;
&#13;

答案 2 :(得分:1)

您可以使用$.Deferred().resolveWith()

function dropLetters($letters) {

  var len = $letters.length - 1;

  var dfd = $.Deferred();

  $letters.each(function(i) {

    var $letter = $(this);

    setTimeout(function() {

      $letter.animate({
        top: offset + 'px'
      }, 300, function() {
        if (i >= len) {
          dfd.resolveWith($(this));
        }
      });

    }, 100 * i);

  });

  return dfd.promise()

}

答案 3 :(得分:1)

正如他们所说,你可以使用$ .Deferred()` 为了说明我添加了一个基于给定代码的示例。 ; - )

//drop individual letters down out of view
    function dropLetters($letters){
        var deferred = jQuery.Deferred();
        
        $letters.each(function(i,elem){
            var $letter = $(elem);

            var timer = setTimeout(function(){        

                $letter.animate({ top: $letter.offset().top-100 }, 300, function(f){
                   if(i+1>=$letters.length){// last letter was animated
                       deferred.resolve();
                   }
                });
              
            }, 300*i );

        });
        return deferred;

    }
dropLetters($('p')).then(function(){alert('finished')});
p{
  position:relative;
  float:left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p><p>A</p>