我有一个用于操纵单个字母的动画循环。它包含在计时器中以创建延迟偏移。每个字母的动画比前一个字母晚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.
另外,我意识到这个问题与另一个问题类似,但它似乎也与此不同。这里提供的答案给出了一些在另一个问题中不存在的不同方法。
答案 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
我对现有检查索引的答案的一个好处是,如果您将动画更改为向后,则必须在两个位置修改代码。请参阅下面的版本,其中字母向后(向前)飞出。
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;
答案 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>