为什么这个动画不稳定,有时会在执行之前有很长的延迟?

时间:2012-01-06 23:23:31

标签: javascript jquery jquery-animate

这个jquery动画在firefox中非常不稳定,在firefox和chrome中它经常会在实际开始动画之前有明显的延迟(约1秒)(如果我在调用onclick处理程序时将代码写入控制台) ,这将立即显示,但动画调用将有一个延迟)。这种延迟不是每次都有,但如果你点击5-6次,你至少会看到它一次。

<!doctype html>
<html>
    <head>
    <title>Test Lag</title>

    <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>

    <style>
        .base
        {
            position: absolute;
            top: 507px;
            left: 0px;
            width: 1000px;
            height: 40px;
            z-index: 0;
        }

        .one
        {
            position: absolute;
            top: 2px;
            left: 2px;
            width: 994px;
            height: 34px;
            background-color: #ffffff;
            border: solid 1px #505050;
            z-index: 3;
            opacity: 0.5;
            filter: alpha(opacity=50);
        }

        .oneA
        {
            position: absolute;
            top: 0px;
            left: 0px;
            width: 966px;
            height: 6px;
            margin: 10px;
            background-color: #999999;
            border: solid #cccccc 4px;

        }

        .two
        {
            position: absolute;
            top: 1px;
            left: 1px;
            width: 996px;
            height: 36px;
            background-color: #e8e8e8;
            border: solid 1px #505050;
            z-index: 2;
            opacity: 0.25;
            filter: alpha(opacity=25);
        }

        .three
        {
            position: absolute;
            top: 0px;
            left: 0px;
            width: 998px;
            height: 38px;
            background-color: #e8e8e8;
            border: solid 1px #505050;
            z-index: 1;
            opacity: 0.12;
            filter: alpha(opacity=12);
        }

        .four
        {
            position: absolute;
            top: 17px;
            left: 17px;
            width: 966px;
            height: 6px;
            background-color: #e8e8e8;
            z-index: 0;
            opacity: 0.5;
            filter: alpha(opacity=50);
        }

        .five
        {
            position: absolute;
            top: 17px;
            left: 17px;
            width: 966px;
            height: 366px;
            z-index: 4;
            overflow: hidden;
        }
    </style>
    </head>
    <body>

    <div id ="base" class="base">
        <div id="one" class="one">
        <div id="oneA" class="oneA"></div>
        </div>
        <div id="two" class="two"></div>
        <div id="three" class="three"></div>
        <div id="four" class="four"></div>
        <div id="five" class="five">There's some text in here.</div>
    </div>

    <script>
       var isOn = false;

       var jq_base = $('#base');
       var jq_one = $('#one');
       var jq_oneA = $('#oneA');
       var jq_two = $('#two');
       var jq_three = $('#three');
       var jq_four = $('#four');

       var baseTop = 96;
       var baseStartTop =507;

       var baseHeight = 400;
       var oneHeight = 394;
       var oneAHeight = 366;
       var twoHeight = 396;
       var threeHeight = 398;
       var fourHeight = 366;

       var baseStartH = 40;
       var oneStartH = 34;
       var oneAStartH = 6;
       var twoStartH = 36;
       var threeStartH = 38;
       var fourStartH = 6

       document.onclick = function()
       {
           //It's opened
           if ( isOn )
           {
               jq_one.animate( { height: oneStartH }, { duration: 300, queue: false } );
               jq_oneA.animate( { height: oneAStartH }, { duration: 300, queue: false } );
               jq_two.animate( { height: twoStartH }, { duration: 300, queue: false } );
               jq_three.animate( { height: threeStartH }, { duration: 300, queue: false } );
               jq_four.animate( { height: fourStartH }, { duration: 300, queue: false } );
               jq_base.animate(
                   { height: baseStartH },
                   {
                       duration: 300,
                       queue: false,
                       step: function (now)
                       {
                           if ( now <= ( baseStartH + 10 ) ) jq_base.animate( { top: baseStartTop }, 800 );
                       }
                   }
               );

               isOn = false;
           }

           //It's closed
           else
           {
               jq_base.animate(
                   { top: baseTop },
                   {
                       duration: 800,
                       step: function (now)
                       {
                           if ( now <= 100 )
                           {
                               jq_base.animate( { height: baseHeight }, { duration: 300, queue: false } );
                               jq_one.animate( { height: oneHeight }, { duration: 300, queue: false } );
                               jq_oneA.animate( { height: oneAHeight }, { duration: 300, queue: false } );
                               jq_two.animate( { height: twoHeight }, { duration: 300, queue: false } );
                               jq_three.animate( { height: threeHeight }, { duration: 300, queue: false } );
                               jq_four.animate( { height: fourHeight }, { duration: 300, queue: false } );
                           }
                       }
                   }
               );
               isOn = true;
           }
       }
    </script>
    </body>
</html>

DEMO:http://jsfiddle.net/fnswz/

1 个答案:

答案 0 :(得分:2)

我认为问题出现在if (isOn)分支的以下部分:

  jq_base.animate(
      { height: baseStartH },
      {
          duration: 300,
          queue: false,
          step: function (now)
          {
              if ( now <= ( baseStartH + 10 ) )
                 jq_base.animate( { top: baseStartTop }, 800 );
          }
      }
  );

具体而言,在该特定step调用的animate()函数内,您启动另一个持续时间相当长(800毫秒)的动画,并且因为它位于step中,即使是如果测试你开始多个动画的持续时间很长。

这意味着虽然该过程达到看起来完成的程度,因为一切都已移动到最终位置,但在幕后这些额外的动画还没有完成运行,所以它没有响应适当的后续点击。如果你将800毫秒动画移出step函数并简单地将它放在后面,它似乎可以使一切工作更加顺畅。 (至少,在Chrome中看起来好多了:正如我在上面的评论中所说,我在这台计算机上没有FF,所以我无法测试。)

以下是我正在谈论的变化的演示:http://jsfiddle.net/fnswz/1/

您可能希望在开始动画时设置标记animationRunning,然后使用animate()的{​​{1}}回调取消设置,以便您可以测试标记并忽略点击直到当前的动画已经完成,但只是上面的改变对我有了很大的改进。

(顺便说一下,为什么在使用jQuery时使用complete?)