从嵌套动画返回结果

Return a result from nested animation

本文关键字:结果 返回 动画 嵌套      更新时间:2023-09-26

我有一个用于操作单个字母的动画循环。它包装在计时器中以创建延迟偏移量。每个字母的动画效果比前一个字母晚 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。

另外,我意识到这个问题与另一个问题相似,但似乎也有所不同。这里提供的答案给出了其他问题中不存在的几种不同方法。

一种利用.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>

您可以从每个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);
}

请注意,您可能需要承诺填充材料 请参阅 http://caniuse.com/#feat=promises

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

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')
});
p, span {
  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>
<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>

您可以使用

$.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()
}

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

//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>