【问题标题】:How do I chain or queue custom functions using JQuery?如何使用 JQuery 链接或排队自定义函数?
【发布时间】:2010-11-08 21:04:09
【问题描述】:

我有多个函数可以对 HTML 的不同部分执行不同的动画。我想链接或排队这些函数,以便它们按顺序而不是同时运行动画。

我正在尝试按顺序自动执行多个事件,以使用户看起来像是在单击不同的按钮或链接。

我可能可以使用回调函数来做到这一点,但是我必须从不同的函数中提取所有动画并以正确的模式重新组合。

jquery“队列”有帮助吗?我无法理解队列中的documentation

例如,JQuery:

 function One() {
        $('div#animateTest1').animate({ left: '+=200' }, 2000);
    }
    function Two() {
        $('div#animateTest2').animate({ width: '+=200' }, 2000);
    }

// Call these functions sequentially so that the animations
// in One() run b/f the animations in Two()
    One();
    Two();

HTML:

    <div id="animatetest" style="width:50px;height:50px;background-color:Aqua;position:absolute;"></div>
    <div id="animatetest2" style="width:50px;height:50px;background-color:red;position:absolute;top:100px;"></div>

谢谢。

编辑: 我用timers 尝试过,但我认为有更好的方法。

编辑#2:

让我更具体一点。我有多个功能绑定到页面不同元素上的单击和悬停事件。通常这些函数彼此无关(它们不相互引用)。我想在不更改现有函数代码的情况下模拟用户经历这些事件。

【问题讨论】:

  • 我认为使用 animate 函数提供的回调功能是可行的方法。
  • 现在有一种方法可以在 jquery 中使用 promise 系统执行此操作。请在此处查看我的答案:stackoverflow.com/a/18216474/726239

标签: jquery animation queue chaining


【解决方案1】:

虽然 Yehuda Katz 的回答在技术上是正确的,但它会随着更大更复杂的动画而迅速膨胀。

我为像你这样的情况制作了一个插件,允许排队功能(如果需要,可以暂停和恢复)。

演示:https://jessengatai.github.io/okaynowthis.js/

使用okaynowthis.js 解决您的问题的方法如下所示:

$('window').load(function(){

    // keyframe 1
    $('body').okaynowthis('keyframe',0,function(){
        $('div#animateTest1').animate({ left: '+=200' }, 2000);
        // + anything else you want to do

    // keyframe 2 (with 2 seconds delay from keyframe 1)
    }).okaynowthis('keyframe',2000,function(){
        $('div#animateTest2').animate({ left: '+=200' }, 2000);
        // + anything else you want to do

    });

});

【讨论】:

    【解决方案2】:

    类似的东西怎么样?

    var f1 = function() {return $(SELECTOR1).animate({ 'prop': 'value' }, 1000)};
    var f2 = function() {return $(SELECTOR2).animate({ 'prop': 'value' }, 1000)};
    var f3 = function() {return $(SELECTOR3).animate({ 'prop': 'value' }, 1000)};
    
    $.when(f1).then(f2).then(f3);
    

    【讨论】:

      【解决方案3】:

      这里不是创建函数的简单方法:

      $('#main').animate({ "top": "0px"}, 3000, function()
         {    $('#navigation').animate({ "left": "100px"},  3000, function() 
              {
                  alert("Call after first and second animation is completed.");
              })
          }
      );
      

      所以,Jquery 默认提供一个一个执行函数的队列。

      【讨论】:

      • 这不能回答问题。该问题要求您使用两个单独的功能。您并不总是将动画链接在一起,有时可能会将自定义函数链接在一起。
      【解决方案4】:

      复制和粘贴............2013 年 7 月 9 日

      <!doctype html>
      <html lang="en">
          enter code here<head>
        <meta charset="utf-8">
        <title>jQuery.queue demo</title>
        <style>
        div { margin:3px; width:40px; height:40px;
              position:absolute; left:0px; top:30px;
              background:green; display:none; }
        div.newcolor { background:blue; }
          </style>
        <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
      </head>
      <body>
      
        <button id="start">Start</button>
        <button id="stop">Stop</button>
        <div></div>
      <script>
         $("#start").click(function () {
            $("div").show("slow");
            $("div").animate({left:'+=200'},5000);
            jQuery.queue( $("div")[0], "fx", function () {
              $(this).addClass("newcolor");
              jQuery.dequeue( this );
            });
            $("div").animate({left:'-=200'},1500);
            jQuery.queue( $("div")[0], "fx", function () {
              $(this).removeClass("newcolor");
              jQuery.dequeue( this );
            });
            $("div").slideUp();
          });
          $("#stop").click(function () {
            jQuery.queue( $("div")[0], "fx", [] );
            $("div").stop();
          });
      </script>
      
      </body>
      </html>
      

      【讨论】:

        【解决方案5】:
        $('div#animateTest1').animate({left: '+=200'},2000, 
        function(){
           $('div#animateTest2').animate({ width: '+=200' }, 2000);
        }
        );
        

        【讨论】:

          【解决方案6】:

          真正简单的修复。

          function One() {
                  $('div#animateTest1').animate({ left: '+=200' }, 2000, Two);
              }
              function Two() {
                  $('div#animateTest2').animate({ width: '+=200' }, 2000);
              }
          
          // Call these functions sequentially so that the animations
          // in One() run b/f the animations in Two()
              One();
          //We no longer need to call Two, as it will be called when 1 is completed.
              //Two();
          

          【讨论】:

            【解决方案7】:

            更安全且 100% 的工作方式是使用变量和 if 分支。 在下面的示例中,我们执行 4 个作业,需要 1 秒,在我们希望函数 f2 运行的作业之后。

            <html><body>
            <div id="a" class="a" />
             <script type="text/javascript">
            var jobs = 0;
            function f1() {
            job(); 
            job();
            job();
            job();    
            };
            
            function f2() {
                if(jobs >3)
                    l("f2");
            };
            
            <!------------------------- ->
            function job() {
                setTimeout(function() {
                    l("j");
                    jobs+=1;
                    f2();
                }, 1000);
            }
            function l(a) {
                document.getElementById('a').innerHTML+=a+"<br />";
            };
            f1();
            
            
            </script></body></html>
            

            【讨论】:

              【解决方案8】:

              我会将第二个作为回调函数运行:

              $('div#animateTest1').animate({ left: '+=200' }, 2000, function(){
                  two();
              });
              

              当第一个动画完成时会运行 two(),如果在这种情况下你在定时队列上有更多的动画,我会使用 jquery timer plugin 而不是 setTimeout(),这在某些情况下非常方便。

              【讨论】:

              • setTimeout 有什么问题?如果该插件在内部使用上述 setTimeout,该插件如何做得更好?
              • @redsquare $.animate 已经创建了一个计时器,那么为什么不让您的代码保持干燥并使用它呢?无需制作多个计时器。
              【解决方案9】:

              @TrippRitter 必须将 .call 附加到回调

              One = function(callback){
                  $('div#animateTest1').animate({ left: '+=200' }, 2000, function(){
                      if(typeof callback == 'function'){
                          callback.call(this);
                      }
                  });
              }
              
              Two = function(){
                  $('div#animateTest2').animate({ width: '+=200' }, 2000);
              }
              
              One(function(){ 
                  Two();
              });
              

              但它与执行以下操作相同

              $('div#animateTest1')
                  .animate({ left: '+=200' }, 2000, 
                  function(){
                     Two();
                  });
              
              Two = function(){
                  $('div#animateTest2').animate({ width: '+=200' }, 2000);
              }
              

              【讨论】:

                【解决方案10】:

                如果回调为空,以下将起作用并且不会出错:

                function One(callback)
                {
                    $('div#animateTest1').animate({ left: '+=200' }, 2000, 
                       function()
                       {
                            if(callback != null)
                            {
                                 callback();
                            }
                       }
                    );
                }
                function Two()
                {
                    $('div#animateTest2').animate({ width: '+=200' }, 2000);
                }
                
                var callback = function(){ Two(); };
                One(callback);
                

                【讨论】:

                  【解决方案11】:

                  jQuery Queue 代码的文档记录并不完善,但基本思路是这样的:

                  $("#some_element").queue("namedQueue", function() {
                    console.log("First");
                    var self = this;
                    setTimeout(function() {
                      $(self).dequeue("namedQueue");
                    }, 1000);
                  });
                  
                  $("#some_element").queue("namedQueue", function() {
                    console.log("Second");
                    var self = this;
                    setTimeout(function() {
                      $(self).dequeue("namedQueue");
                    }, 1000);
                  });
                  
                  $("#some_element").queue("namedQueue", function() {
                    console.log("Third");
                  });
                  
                  $("#some_element").dequeue("namedQueue");
                  

                  如果你运行这段代码,你会在控制台看到“First”,停顿1s,在控制台看到“Second”,再停顿1s,最后在控制台看到“Third”。

                  基本思想是您可以将任意数量的命名队列绑定到一个元素。您可以通过调用dequeue 从队列中删除一个元素。您可以根据需要手动多次执行此操作,但如果您希望队列自动运行,您只需在 queued up 函数中调用 dequeue

                  jQuery 中的动画都在名为fx 的队列中运行。当您为元素设置动画时,它会自动将新动画添加到队列中,如果当前没有动画正在运行,则调用 dequeue。如果您愿意,您可以将自己的回调插入fx 队列;您只需要在最后手动调用dequeue(与任何其他队列使用一样)。

                  【讨论】:

                  • $('div#myDiv1').queue('fx',fn1); $('div#myDiv2').queue('fx',fn2);请注意,它们是并行执行的,而不是顺序执行的。因此,如果您有两个函数,在不同的元素上使用 animate(),它们也将并行执行。因此,仅使用队列将不允许顺序执行。
                  • 如果你在 .queue 之前使用全局对象而不是单个选择器
                  • 仅仅为了链接函数和效果,我们可以使用承诺系统,这是我在 jQuery 中实现的 .promise() 。在这里查看答案,例如:stackoverflow.com/a/18216474/726239
                  【解决方案12】:

                  在我的一个 Web 项目中,我必须根据触发的事件执行各种操作序列。我使用回调(类似于访问者模式)来做到这一点。我创建了一个对象来包装任何函数或一组动作。然后我会将这些包装器排队;数组工作正常。当事件触发时,我将遍历数组,调用我的对象的特殊方法,该方法接受回调。该回调触发了我的迭代继续。

                  要包装函数,您需要了解the apply function。 apply 函数接受一个对象作为作用域和一个参数数组。这样你就不需要知道你要包装的函数的任何信息。

                  【讨论】:

                    【解决方案13】:

                    我会创建一个函数数组,并添加你想要排队的每个函数。

                    然后我会附加一个函数调用,它循环遍历数组并通过 jQuery 将每个函数调用到事件。

                    您可能可以为 jQuery 创建一个非常简单的插件,它也可以在内部处理这个问题。

                    【讨论】:

                    【解决方案14】:

                    假设您想将 OneTwo 保留为单独的函数, 你可以这样做:

                    function One(callback) {
                        $('div#animateTest1').animate({ left: '+=200' }, 2000, 
                            function(e) { callback(); });
                    }
                    function Two() {
                        $('div#animateTest2').animate({ width: '+=200' }, 2000);
                    }
                    
                    // Call these functions sequentially so that the animations
                    // in One() run b/f the animations in Two()
                        One(Two);
                    

                    【讨论】:

                    • 如果传入的回调参数为'null'会怎样?还能用吗?
                    • 不,你应该在那里做一些错误处理。我在 SO 编辑框中写了这个,没有过多考虑错误处理或尝试运行它。
                    • 我并不是要批评您的错误处理技巧。 :) 我在问 b/c 什么时候真正的用户会调用这些函数,实际上点击链接应该没有回调(null)。只有当代码自动执行这些步骤时,才需要回调。
                    • 我知道它已经有多年历史了,但编辑了这个答案,为代码中添加了一些错误处理,只是为了任何遇到这个问题并且想知道如何做到这一点的人,假设我没有搞砸输入它出;)
                    【解决方案15】:

                    只要动画间隔已经定义在 2000 毫秒,您可以在 2000 毫秒内进行第二次调用:

                    One();
                    SetTimeout(function(){
                      Two();
                    }, 2000);
                    

                    【讨论】:

                    • 我知道我可以使用计时器或 setTimeout,但我认为有某种队列可以放入我的函数。
                    • ...不用担心时间。
                    猜你喜欢
                    • 1970-01-01
                    • 2011-05-05
                    • 2011-04-26
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-07-09
                    • 2017-04-26
                    相关资源
                    最近更新 更多