Javascript 强制操作从$.each循环排队

Javascript 强制操作从$.each循环排队,javascript,jquery,triggers,Javascript,Jquery,Triggers,我正在使用jquery制作html元素卡的动画。我需要设置一个交易动作的动画“一个为你,一个为我,一个为你,一个为我…”,所以我希望在下一个动作开始之前,这些牌能够完全设置移动位置的动画。我用$来创建卡片,每个函数都用$来调用动画,以避免不必要的循环。将卡添加到页面时,动画开始,但循环随后移动到下一张卡,而不等待动画完成。这使得所有的卡片看起来都是在同一时间而不是按顺序进行动画制作的。如何使循环等待动画回调?这可以用触发器来完成吗?我可以手动排队吗 我的错误代码的精简版本: var card =

我正在使用jquery制作html元素卡的动画。我需要设置一个交易动作的动画“一个为你,一个为我,一个为你,一个为我…”,所以我希望在下一个动作开始之前,这些牌能够完全设置移动位置的动画。我用$来创建卡片,每个函数都用$来调用动画,以避免不必要的循环。将卡添加到页面时,动画开始,但循环随后移动到下一张卡,而不等待动画完成。这使得所有的卡片看起来都是在同一时间而不是按顺序进行动画制作的。如何使循环等待动画回调?这可以用触发器来完成吗?我可以手动排队吗

我的错误代码的精简版本:

var card = [
  { id:1, pos:{ x:100, y:100 } },
  { id:2, pos:{ x:150, y:105 } },
  { id:3, pos:{ x:200, y:110 } }
];

$.each(card, function() {
  $('#card_' + this.id).animate({ top:this.pos.y, left:this.pos.x });
});

Demo@

您不能在JavaScript循环中执行此操作,必须在调用中使用回调参数来触发下一张卡的动画。大概是这样的:

var card = [
    { id:1, pos:{ x:100, y:100 } },
    { id:2, pos:{ x:150, y:105 } },
    { id:3, pos:{ x:200, y:110 } }
];

doOne(0);

function doOne(index) {
    var thisCard = card[index];
    if (thisCard) {
        $('#card_' + thisCard.id).animate({
            top:    thisCard.pos.y,
            left:   thisCard.pos.x
        }, function() {
            doOne(index + 1);
        });
    }
}
$.each(card, function(i) {
  $('#card_'+this.id).delay(i*400).animate({ top:this.pos.y, left:this.pos.x });
});
var card = [
  { id:1, pos:{ left:100, top:100 } },
  { id:2, pos:{ left:150, top:105 } },
  { id:3, pos:{ left:200, top:110 } }
];

$.each(card, function(i) {
  $('#card_'+this.id).delay(i*400).animate(this.pos);
});

当然,我会将所有这些都包装在一个函数中,以避免创建不必要的全局符号。

在JavaScript循环中不能这样做,必须在调用中使用回调参数来触发下一张卡的动画。大概是这样的:

var card = [
    { id:1, pos:{ x:100, y:100 } },
    { id:2, pos:{ x:150, y:105 } },
    { id:3, pos:{ x:200, y:110 } }
];

doOne(0);

function doOne(index) {
    var thisCard = card[index];
    if (thisCard) {
        $('#card_' + thisCard.id).animate({
            top:    thisCard.pos.y,
            left:   thisCard.pos.x
        }, function() {
            doOne(index + 1);
        });
    }
}
$.each(card, function(i) {
  $('#card_'+this.id).delay(i*400).animate({ top:this.pos.y, left:this.pos.x });
});
var card = [
  { id:1, pos:{ left:100, top:100 } },
  { id:2, pos:{ left:150, top:105 } },
  { id:3, pos:{ left:200, top:110 } }
];

$.each(card, function(i) {
  $('#card_'+this.id).delay(i*400).animate(this.pos);
});
当然,我会将所有这些都包装在一个函数中,以避免创建不必要的全局符号。

您可以使用,如下所示:

var card = [
    { id:1, pos:{ x:100, y:100 } },
    { id:2, pos:{ x:150, y:105 } },
    { id:3, pos:{ x:200, y:110 } }
];

doOne(0);

function doOne(index) {
    var thisCard = card[index];
    if (thisCard) {
        $('#card_' + thisCard.id).animate({
            top:    thisCard.pos.y,
            left:   thisCard.pos.x
        }, function() {
            doOne(index + 1);
        });
    }
}
$.each(card, function(i) {
  $('#card_'+this.id).delay(i*400).animate({ top:this.pos.y, left:this.pos.x });
});
var card = [
  { id:1, pos:{ left:100, top:100 } },
  { id:2, pos:{ left:150, top:105 } },
  { id:3, pos:{ left:200, top:110 } }
];

$.each(card, function(i) {
  $('#card_'+this.id).delay(i*400).animate(this.pos);
});

默认情况下,每个动画需要400毫秒,回调的第一个参数是索引,因此第一个延迟为0*400,第二个延迟为1*400,以此类推……有效地一个接一个地运行它们

此外,如果不需要这些x/y格式变量,则可以将它们存储为“上/左”,并直接传递这些动画属性,如下所示:

var card = [
    { id:1, pos:{ x:100, y:100 } },
    { id:2, pos:{ x:150, y:105 } },
    { id:3, pos:{ x:200, y:110 } }
];

doOne(0);

function doOne(index) {
    var thisCard = card[index];
    if (thisCard) {
        $('#card_' + thisCard.id).animate({
            top:    thisCard.pos.y,
            left:   thisCard.pos.x
        }, function() {
            doOne(index + 1);
        });
    }
}
$.each(card, function(i) {
  $('#card_'+this.id).delay(i*400).animate({ top:this.pos.y, left:this.pos.x });
});
var card = [
  { id:1, pos:{ left:100, top:100 } },
  { id:2, pos:{ left:150, top:105 } },
  { id:3, pos:{ left:200, top:110 } }
];

$.each(card, function(i) {
  $('#card_'+this.id).delay(i*400).animate(this.pos);
});
您可以这样使用:

var card = [
    { id:1, pos:{ x:100, y:100 } },
    { id:2, pos:{ x:150, y:105 } },
    { id:3, pos:{ x:200, y:110 } }
];

doOne(0);

function doOne(index) {
    var thisCard = card[index];
    if (thisCard) {
        $('#card_' + thisCard.id).animate({
            top:    thisCard.pos.y,
            left:   thisCard.pos.x
        }, function() {
            doOne(index + 1);
        });
    }
}
$.each(card, function(i) {
  $('#card_'+this.id).delay(i*400).animate({ top:this.pos.y, left:this.pos.x });
});
var card = [
  { id:1, pos:{ left:100, top:100 } },
  { id:2, pos:{ left:150, top:105 } },
  { id:3, pos:{ left:200, top:110 } }
];

$.each(card, function(i) {
  $('#card_'+this.id).delay(i*400).animate(this.pos);
});

默认情况下,每个动画需要400毫秒,回调的第一个参数是索引,因此第一个延迟为0*400,第二个延迟为1*400,以此类推……有效地一个接一个地运行它们

此外,如果不需要这些x/y格式变量,则可以将它们存储为“上/左”,并直接传递这些动画属性,如下所示:

var card = [
    { id:1, pos:{ x:100, y:100 } },
    { id:2, pos:{ x:150, y:105 } },
    { id:3, pos:{ x:200, y:110 } }
];

doOne(0);

function doOne(index) {
    var thisCard = card[index];
    if (thisCard) {
        $('#card_' + thisCard.id).animate({
            top:    thisCard.pos.y,
            left:   thisCard.pos.x
        }, function() {
            doOne(index + 1);
        });
    }
}
$.each(card, function(i) {
  $('#card_'+this.id).delay(i*400).animate({ top:this.pos.y, left:this.pos.x });
});
var card = [
  { id:1, pos:{ left:100, top:100 } },
  { id:2, pos:{ left:150, top:105 } },
  { id:3, pos:{ left:200, top:110 } }
];

$.each(card, function(i) {
  $('#card_'+this.id).delay(i*400).animate(this.pos);
});

正常回调可能会导致混乱,因为每个动画都需要在其回调中调用下一个。当然,您可以使用计时器或延迟来创建暂停,但这并不保证在下一个动画开始之前完成整个动画。如果动画所花费的时间少于超时时间,则每个动画之间可能会有一个暂停

另一种选择是研究承诺和未来。虽然我没有执行动画,但我的应用程序具有必须按特定顺序处理的逻辑。我一直在利用图书馆来帮助简化事情。一开始它可能看起来很吓人,但它确实非常强大。看看.chainify方法


我意识到这对于您的简单用例来说可能有些过分,但我认为了解承诺是值得的。

这可能会让正常回调变得混乱,因为每个动画都需要在回调中调用下一个。当然,您可以使用计时器或延迟来创建暂停,但这并不保证在下一个动画开始之前完成整个动画。如果动画所花费的时间少于超时时间,则每个动画之间可能会有一个暂停

另一种选择是研究承诺和未来。虽然我没有执行动画,但我的应用程序具有必须按特定顺序处理的逻辑。我一直在利用图书馆来帮助简化事情。一开始它可能看起来很吓人,但它确实非常强大。看看.chainify方法


我意识到这对于您的简单用例来说可能有些过分,但我认为了解承诺是值得的。

这里有另一种方法:

var card = [
    {elem: $('#card_1'), id:1, pos:{ x:100, y:100 } },
    {elem: $('#card_2'), id:2, pos:{ x:150, y:105 } },
    {elem: $('#card_3'), id:3, pos:{ x:200, y:110 } }
];

(function loop(arr, len){
    if(len--){      
        arr[len].elem.animate({top: arr[len].pos.y, left: arr[len].pos.x}, 400, function(){
           loop(arr, len);
        });     
    }
}(card.reverse(), card.length));

行动中:

这里有另一种方法:

var card = [
    {elem: $('#card_1'), id:1, pos:{ x:100, y:100 } },
    {elem: $('#card_2'), id:2, pos:{ x:150, y:105 } },
    {elem: $('#card_3'), id:3, pos:{ x:200, y:110 } }
];

(function loop(arr, len){
    if(len--){      
        arr[len].elem.animate({top: arr[len].pos.y, left: arr[len].pos.x}, 400, function(){
           loop(arr, len);
        });     
    }
}(card.reverse(), card.length));

在实际操作中:

对于一堆卡片,时间的不确定性很可能成为一个问题。@TJCrowder-不会的,它是隐藏的setInterval。@Nick:setInterval有各种各样的不确定性。@TJCrowder-我同意,但它们在内部是一致的,是什么延迟了一个延迟了另一个。@Nick:不,每个间隔都独立于其他间隔。它们唯一的交互时间是当一个时间间隔到期时,另一个时间间隔的代码已经在运行,从而延迟了它。这就是问题的症结所在。有了一堆卡片,时间的不确定性很可能会成为一个问题。@TJCrowder-不会的,它是隐藏的setInterval。@Nick:setInterval有各种各样的不确定性。@TJCrowder-我同意,但它们在内部是一致的,是什么延迟了一个延迟了另一个。@Nick:不,每个间隔都独立于其他间隔。它们唯一的交互时间是当一个时间间隔到期时,另一个时间间隔的代码已经在运行,从而延迟了它。正确答案是正确的,正确设计的异步函数,如animate,总是能够在完成后调用另一个函数。那是触发的地方
下一个动画。+1正确答案,正确设计的异步函数(如animate)在完成后始终能够调用另一个函数。这是触发下一个动画的地方。这种方法颠倒了卡片动画的顺序:@Nick:的确如此,但这只是另一种处理方式。要恢复原来的顺序,这是一个简单的修复。对我来说,这有相同的时间问题或没有,根据尼克!作为尼克的方法,@T.J.我同意。我意识到我实际上没有理由使用之前的模式,所以我改变了它,将下一个调用放入.animate的回调中。@jAndy:是的,这也是我首选的方法。顺便说一句,仅供参考,在IE上,您正在创建两个函数任何时候,当您有一个命名函数声明也用作表达式的右侧时,MS的JScript都会创建其中两个声明,一个来自声明,另一个来自表达式。您的第一个调用是调用由表达式生成的函数,然后该函数调用由声明创建的函数。在这种情况下没有关系,但我想指出这一点,因为在一些模式中,人们最终会得到他们创建的几乎每个函数的两个副本!:-这种方法颠倒了卡片动画的顺序:@Nick:的确如此,但这只是另一种处理方式。要恢复原来的顺序,这是一个简单的修复。对我来说,这有相同的时间问题或没有,根据尼克!作为尼克的方法,@T.J.我同意。我意识到我实际上没有理由使用之前的模式,所以我改变了它,将下一个调用放入.animate的回调中。@jAndy:是的,这也是我首选的方法。顺便说一句,仅供参考,在IE上,您正在创建两个函数任何时候,当您有一个命名函数声明也用作表达式的右侧时,MS的JScript都会创建其中两个声明,一个来自声明,另一个来自表达式。您的第一个调用是调用由表达式生成的函数,然后该函数调用由声明创建的函数。在这种情况下没有关系,但我想指出这一点,因为在一些模式中,人们最终会得到他们创建的几乎每个函数的两个副本!:-