4

我在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);
}

showDialogueandprepareDialogue是我创建的延迟和淡入淡出文本的方法。那工作正常。基本上,我只是想让文本在特定时间后更改文本区域选择器中的文本。当前正在发生的是所有功能都在同时运行,因此同时触发了文本更改效果。我想做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;
};

解决方案EDIT2:感谢大家的回复,以及首先建议使用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 链接,如果您想查看它的实际效果。

4

5 回答 5

6

正如@whoughton 指出的那样,这是一种使用承诺的方法:

使用 .promise() ( 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>

查询:

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 函数中传递需要链接的所有函数的数组,该函数递归运行,直到所有函数完成。他们在上一个动画完成之前暂停下一个函数的执行的方式是使用.promise()jquery 的功能。

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

真正的诀窍在于理解.promise()的工作原理。它等待在传递给它的所有选择器上运行的所有动画。因此,在单个效果功能中,您可以根据需要对任意数量的元素运行效果。只要您返回正确的选择器,您就应该很好。

例如,假设在所有这些效果中,您想在所有 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);
          });

    }
于 2013-08-13T18:26:32.650 回答
2

我会推荐使用一个promises系统,jQuery有它自己的实现:

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

于 2013-08-13T15:58:14.500 回答
1

一般来说,您在 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();
于 2013-08-13T16:03:44.573 回答
0

这是一个小提琴,展示了你正在尝试做的一个非常简单的版本。我认为。 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/ 我不认为有任何更有效的,但在这里你带着循环善良。

于 2013-08-13T16:20:05.060 回答
-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);
}
于 2013-08-13T15:54:45.733 回答