按特定顺序运行具有效果的jQuery函数

Running jQuery functions with effects in a specific order

本文关键字:jQuery 函数 有效果 定顺序 运行      更新时间:2023-09-26

我在javascript函数中有一些jQuery,它可以更改页面上的文本,并在特定的时间间隔内淡入淡出。我希望在每个函数完成其效果后,这些函数一个接一个地按顺序运行。

dialogueExchange1();
dialogueExchange2();
dialogueExchange3();
function dialogueExchange1() {
  $('.text-area1').text("hey");
  $('.text-area1').delay(1000).showDialogue(800, 3000).prepareDialogue(800, "hey, are you awake?");
}
function dialogueExchange2() {
  $('.text-area1').delay(900).showDialogue(800, 4000).prepareDialogue(800, "wake up").delay(900);
  $('.text-area2').text("...");
  $('.text-area2').delay(1200).showDialogue(800, 1500).fadeOut(800);
}
function dialogueExchange3() {
  $('.text-area1').delay(900).showDialogue(800, 4000).prepareDialogue(800, "let's go").delay(900);
  $('.text-area2').text("not yet");
  $('.text-area2').delay(1200).showDialogue(800, 1500).fadeOut(800);
}

showDialogueprepareDialogue是我创建的延迟和淡入淡出文本的方法。这很好。基本上,我只是想让文本在特定时间后在文本区域选择器中进行更改。目前发生的情况是,所有函数都在同一时间运行,从而同时激发文本更改效果。我想让dialogueExchange1做它的效果,然后当它完成时,让dialogueExchange2做它的影响,然后当完成时,等等。

我已经尝试过通过下面的解决方案来处理队列、超时和回调,但我还没有让它做我想做的事情:

如何避免回调链?

如何使用JQuery链接或排队自定义函数?

我以前也做过这样的工作,只是把所有的文本更改方法链接在一行代码中,做我想做的事情,但这看起来很糟糕。将其分解为多个函数并按顺序运行会使其更有组织性,并有助于跟踪文本更改和延迟时间。谢谢

编辑:showDialogueprepareDialogue按要求工作

$.fn.showDialogue = function(fadeInTime, showTextTime) {
    this.fadeIn(fadeInTime).delay(showTextTime);
    return this;
};
$.fn.prepareDialogue = function(fadeOutTime, dialogue) {
    this.fadeOut(fadeOutTime, function() {
        $(this).html(dialogue);
    });
    return this;
};

解决方案第2版:感谢大家的回复,感谢whoughton首次建议使用promise()。这是我目前的解决方案,但我相信我会在看到Shaunak的答案后对其进行重构和更改。

dialogueExchange1();
function dialogueExchange1() {
    $('.text-area1').text("hey");
    $('.text-area1').delay(1000).showDialogue(800, 3000).prepareDialogue(800, "hey, are you awake?");
    $('.text-area1, .text-area2, .text-area3').promise().done(function() {
        dialogueExchange2();     
    });
}
function dialogueExchange2() {
    $('.text-area1').delay(900).showDialogue(800, 4000).prepareDialogue(800, "wake up");
    $('.text-area3').text("...");
    $('.text-area3').delay(1800).showDialogue(800, 1500).fadeOut(800);
    $('.text-area1, .text-area2, .text-area3').promise().done(function() {
        dialogueExchange3();     
    });
}
function dialogueExchange3() {
    $('.text-area1').delay(900).showDialogue(800, 4000).prepareDialogue(800, "come on let's go");
    $('.text-area2').text("hold on");
    $('.text-area2').delay(1200).showDialogue(800, 1500).fadeOut(800);
}

这样,它给了我很大的灵活性来改进延迟时间,以反映和模仿对话。下一个函数只有在函数内的效果完成时才运行,promise()使其成为可能。这里有一个jsFiddle链接,如果你想看看它的实际操作。

正如@whoughton所指出的,这里有一种通过承诺来实现这一点的方法:

使用.proise()的解决方案(jsfiddle)

Html:

<div class="hasEffects effect1"> Div 1</div>
<div class="hasEffects effect2"> Div 2</div>
<div class="hasEffects effect3"> Div 3</div>
<button id="animate">animate</button>

Jquery:

effects1 = function(){
    $(".effect1").effect("shake", {}, 1000);
    return $(".effect1");
// or you can return $(".hasEffects"); if you are running effects on multiple elements
};
effects2 = function(){
    $(".effect2").effect("shake", {}, 1000);
    return $(".effect2");
};
effects3 = function(){
    $(".effect3").effect("shake", {}, 1000);
    return $(".effect3");
};
$("#animate").click(function(){
    runAnimations([effects1,effects2,effects3]);
});
 runAnimations = function(functionArray) {
    //extract the first function        
    var func = functionArray.splice(0, 1);
    //run it. and wait till its finished 
    func[0]().promise().done(function() {
        //then call run animations again on remaining array
        if (functionArray.length > 0) runAnimations(functionArray);
    });
}

这是jsfiddle

这是如何工作的

您可以在runAnimation函数中传递一个需要链接的所有函数的数组,该函数将递归运行,直到所有函数完成。在上一个函数的动画完成之前,它暂停下一个函数执行的方法是使用jquery的.promise()特性。

每次运行runAnimation()时,它都会提取数组中的第一个函数并运行它,在为该函数执行.proimise().done()后,它会用剩余的数组再次调用runAnimation()

真正的诀窍在于理解.procise()是如何工作的。它等待所有传递给它的选择器上运行的所有动画。因此,在单独的效果函数中,你可以在任意多的元素上运行效果。只要您返回正确的选择器,您就应该是好的。

例如,假设在所有的e效果中,您希望在所有3个div上运行3个不同的效果。没关系,只需从函数中返回$("hasEffects"),它就会工作。:)

在您的情况下

在您的特定情况下,以下是如何使用此示例。在所有元素上添加一个分组类,例如class="hasEffects"。并从动画函数中为它们返回一个jquery选择器。然后使用runAnimation将它们链接起来。以下是它的外观:

function dialogueExchange1() {
   $('.text-area1').text("hey");
   $('.text-area1').delay(1000).showDialogue(800, 3000).prepareDialogue(800, "hey, are you awake?");
   return $(".hasEffects");
}
function dialogueExchange2() {
   $('.text-area1').delay(900).showDialogue(800, 4000).prepareDialogue(800, "wake up").delay(900);
   $('.text-area2').text("...");
   $('.text-area2').delay(1200).showDialogue(800, 1500).fadeOut(800);
   return $(".hasEffects");
}
function dialogueExchange3() {
   $('.text-area1').delay(900).showDialogue(800, 4000).prepareDialogue(800, "let's go").delay(900);
   $('.text-area2').text("not yet");
   $('.text-area2').delay(1200).showDialogue(800, 1500).fadeOut(800);
   return $(".hasEffects");
}
runAnimations([dialogueExchange1,dialogueExchange2,dialogueExchange3]);
runAnimations = function(functionArray){
        var func = functionArray.splice(0,1);
          func[0]().promise().done(function(){
            if(functionArray.length > 0 ) runAnimations(functionArray);
          });
    }

我建议使用promise系统,jQuery有自己的实现:

http://api.jquery.com/promise/

通常,在jQuery中执行此操作的方式有两种。首先介绍一下Javascript中的异步内容。

当您调用fadeOut()时,它的行为就像有两个执行线程。其中一个线程开始对元素进行一系列更改,使其越来越不可见。另一个线程继续执行fadeOut()之后的命令。也许是其他屏幕元素的逐渐消失。你需要了解这是如何工作的,因为我使用"线程"这个词非常松散,细节也不一样。但你可以把它看作是同时发生的两件事。这就是为什么您可以同时看到所有元素的动画。(有时这是想要的行为。)

一种使动画按顺序发生的方法是这样的。你在同一个元素上字符串调用动画:

$(whatever).delay(400).fadeIn(300).

因此,同一元素上的动画在开始之前等待先前排队的动画完成。

另一种方式允许多个元素按顺序变化:

$(whatever).delay(400).fadeOut(300, function() {
    $(whateverelse).fadeIn(400);
}

直到fadeOut()完成后,才会调用该函数。所以fadeIn()直到另一个结束才开始。

你的情况更复杂,部分原因是这两种方法,但可以使用这两种方式。您的方法可能需要接受一个附加参数,该参数是在这些动画完成时要调用的函数。

注意:由于您的两个方法只处理"this"并返回"this",因此它们会将动画添加到您正在处理的同一元素中。这些动画应保持顺序。

只有当你需要一个元素中的动画来等待另一个元素的动画时,你才需要第二个形式

注2:我注意到这些函数将动画挂在相同的元素上,所以你可以做这样的事情:

function dialogueExchange2() {
  $('.text-area1').delay(900).showDialogue(800, 4000).prepareDialogue(800, "wake up").delay(900,
    function() {
      $('.text-area2').text("...");
      $('.text-area2').delay(1200).showDialogue(800, 1500).fadeOut(800);
    });
}
function dialogueExchange3() {
  $('.text-area2').delay(1, function() { // this just makes #3 wait for #2 to finish
    $('.text-area1').delay(900).showDialogue(800, 4000).prepareDialogue(800, "let's go").delay(900,
      function() {
        $('.text-area2').text("not yet");
        $('.text-area2').delay(1200).showDialogue(800, 1500).fadeOut(800);
      });
  });
}

当你打电话给他们时,你会这样做:

dialogueExchange1();
dialogueExchange2();
dialogueExchange3();

这里有一个小提琴来展示你正在尝试做的事情的一个非常简单的版本。我想。http://jsfiddle.net/wembz/

每个项目都应该在设置的延迟后运行,因为它们都是异步的。例如,如果第一个动画长1500毫秒,并且您希望文本在该动画完成后更改300毫秒,则会延迟1800毫秒。。。希望这是有道理的。

var timeoutQueue = [],
    $ta1 = $('.text-area1'),
    $ta2 = $('.text-area2');
//Each of the DELAY_IN_MS in the functions should be the exact point in ms where the animation should occur.
timeoutQueue.push(
    setTimeout(function(){
        $ta1.text("hey");
    }, DELAY_IN_MS)
);
timeoutQueue.push(
    setTimeout(function(){
        $ta1.showDialogue(800, 3000);
    }, DELAY_IN_MS)
);
timeoutQueue.push(
    setTimeout(function(){
        $ta1.prepareDialogue(800, "hey, are you awake?");
    }, DELAY_IN_MS)
);
timeoutQueue.push(
    setTimeout(function(){
        $ta1.showDialogue(800, 4000);
    }, DELAY_IN_MS)
);
timeoutQueue.push(
    setTimeout(function(){
        $ta1.prepareDialogue(800, "wake up");
    }, DELAY_IN_MS)
);
timeoutQueue.push(
    setTimeout(function(){
        $ta2.text("...");
    }, DELAY_IN_MS)
);
timeoutQueue.push(
    setTimeout(function(){
        $ta2.showDialogue(800, 1500)
    }, DELAY_IN_MS)
);
timeoutQueue.push(
    setTimeout(function(){
        $ta2.fadeOut(800)
    }, DELAY_IN_MS)
);
timeoutQueue.push(
    setTimeout(function(){
        $ta1.showDialogue(800, 4000);
    }, DELAY_IN_MS)
);
timeoutQueue.push(
    setTimeout(function(){
        $ta1.prepareDialogue(800, "let's go");
    }, DELAY_IN_MS)
);
timeoutQueue.push(
    setTimeout(function(){
        $ta2.text("not yet");
    }, DELAY_IN_MS)
);
timeoutQueue.push(
    setTimeout(function(){
        $ta2.showDialogue(800, 1500);
    }, DELAY_IN_MS)
);
timeoutQueue.push(
    setTimeout(function(){
        $ta2.fadeOut(800);
    }, DELAY_IN_MS)
);

编辑:http://jsfiddle.net/AmqHB/

var timeoutQueue = [],
    currentDelay = 500;
    $ta1 = $('#mytext');
function newSequence(fn, expectedlength, delayafter){
    timeoutQueue.push( setTimeout(fn, currentDelay) );
    currentDelay += (expectedlength + delayafter);
}
newSequence(function(){$ta1.fadeOut(500);},500,1000);
newSequence(function(){$ta1.text("hey").fadeIn(500);},500,1000);
newSequence(function(){$ta1.fadeOut(500);},500,1000);
newSequence(function(){$ta1.text("It Can't possibly be this simple.").fadeIn(500);},500,1000);

编辑2:http://jsfiddle.net/AmqHB/1/我不认为有什么比这更有效的了,但你可以带着疯狂的善良。

这个呢:

dialogueExchange1();

function dialogueExchange1() {
  $('.text-area1').text("hey");
  $('.text-area1').delay(1000).showDialogue(800, 3000).prepareDialogue(800, "hey, are you awake?");
dialogueExchange2();
}
function dialogueExchange2() {
  $('.text-area1').delay(900).showDialogue(800, 4000).prepareDialogue(800, "wake up").delay(900);
  $('.text-area2').text("...");
  $('.text-area2').delay(1200).showDialogue(800, 1500).fadeOut(800, function(){
  dialogueExchange3();
  });
}
function dialogueExchange3() {
  $('.text-area1').delay(900).showDialogue(800, 4000).prepareDialogue(800, "let's go").delay(900);
  $('.text-area2').text("not yet");
  $('.text-area2').delay(1200).showDialogue(800, 1500).fadeOut(800);
}