3

我正在继续之前的帖子,但我想我会打开一个新线程,因为它采用不同的方法并且有更多实际代码。无论如何,我试图让一个无限循环与 div 滚动通过一个窗口(另一篇文章有​​一个图像,下面的代码有效)。

<html>
    <head>
        <meta http-equiv="Content-type" content="text/html; charset=utf-8">
        <title>Bleh...</title>
        <style type="text/css" media="screen">
            body {
                padding: 0;
                text-align: center;
            }

            #container {
              width: 1000px;
              padding: 10px;
              border: 1px solid #bfbfbf;
              margin: 0 auto;
              position: relative;
            }

            #window {
              width: 400px;
              height: 100px;
              padding: 10px;
              border: 3px solid #666;
              margin: 0 auto;
            }

            .box {
              height: 100px;
              width: 100px;
              border: 1px solid #666666;
              position: absolute;
              z-index: -1;
            }

            .red { background-color: #ff6868;}
            .green { background-color: 7cd980;}
            .blue { background-color: #5793ea;}
            .yellow { background-color: #f9f69e;}
            .purple { background-color: #ffbffc;}
            .cyan { background-color: #bff3ff;}

        </style>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript"></script>
        <script type="text/javascript" charset="utf-8">
            $(window).load(function() { 
               arrangeBoxes();
               setInterval('shiftLeft()', 3000);
            });

            // arrange the boxes to be aligned in a row
            function arrangeBoxes() {
              $('.box').each( function(i, item) {
                var position = $('#window').position().left + 3 + i * ( $(item).width() + 10 );
                $(item).css('left', position+'px')
              });
            }

            // shifts all the boxes to the left, then checks if any left the window
            function shiftLeft() {
              $('.box').animate({'left' : "-=100px"}, 3000, 'linear');
              checkEdge();
            }

            // returns the new location for the box that exited the window
            function getNewPosition() {
              return $('.box:last').position().left + $('.box:last').outerWidth() + 10;
            }

            // if the box is outside the window, move it to the end
            function checkEdge() {
              var windowsLeftEdge = $('#window').position().left;

              $('.box').each( function(i, box) {

                // right edge of the sliding box
                var boxRightEdge = $(box).position().left + $(box).width();

                // position of last box + width + 10px
                var newPosition = getNewPosition();
                if ( $(box).attr('class').indexOf('red') >=0 ) {
                  console.log('box edge: ' + boxRightEdge + ' window edge: ' + windowsLeftEdge + ' new pos: ' +newPosition);
                }

                if ( parseFloat(boxRightEdge) < parseFloat(windowsLeftEdge) ) { 
                  $(box).css('left', newPosition);
                  $(box).remove().appendTo('#window');
                  first = $('.box:first').attr('class');
                  console.log('first is ' +  first);
                }
              });


            }
        </script>
    </head>
    <body id="index">
        <div id="container">
          <div id="window">
            <div class="box red"></div>
            <div class="box green"></div>
            <div class="box blue"></div>
            <div class="box yellow"></div>
            <div class="box purple"></div>
            <div class="box cyan"></div>
          </div>
        </div>
    </body>
</html>

无论如何,问题是我可以让框向左移动,但是当我运行整个过程时,我无法让前导框弹回到行尾。当我分别运行每个功能(使用萤火虫) -

>> $('.box').animate({'left' : "-=100px"}, 3000, 'linear');
>> checkEdge()

它工作得很好。当我把它们放在一起时,我只是从右到左连续运动,直到盒子离开屏幕,所以这一定是它们交互的方式。我希望这是有道理的(如果没有,请将上面的代码块保存为 html 文件并在浏览器中运行)。我已经坚持了一段时间,所以任何帮助都会很棒。谢谢。

4

2 回答 2

4

您需要像这样设置回调

$('.box').animate({'left' : "-=100px"}, 3000, 'linear', checkEdge());

checkEdge()不是checkEdge

在此处查看有效的解决方案http://jsbin.com/uceqi(只需复制粘贴您的代码)


如果您将牙套放在一边,实际上会有所不同。带有大括号的版本checkEdge()每个动画执行一次(老实说,它实际上是checkEdge 在动画开始checkEdge()之前执行的。当到达$...animte(..)语句时甚至在animate()它本身执行之前调用该函数。checkEdge将导致函数作为参数传入,通常是正确的方式去)。

不带大括号的版本checkEdge会针对与选择器匹配的元素数量执行一次。在这种情况下 6 次。

所以从技术上讲,你的方法是正确的,因为它会在每个动画元素和动画之后触发一次回调。但是执行checkEdge一次这显然不是作者的意图(检查 divs in 的循环checkEdge)。当您在所有 div 上循环多次时,也会导致严重滞后

6divs 动画->6x 回调->在所有 divs 中触发回调循环==>36x 执行匿名函数checkEdge()

所以实际的问题是回调被同时触发 6 次。因此我们有一个竞争条件并且动画混乱了。由于多个checkEdge()调用同时在重新定位 div 上工作。

但是您只注意到这一点,因为 (shiftLeft) 中的animation-speed和 间隔setInterval是相同的。它们会有所不同((间隔+〜1000ms)>动画速度)那么它也可以正常工作。但当然动画不会是流畅的。就像shitfLeft()动画停止后 1 秒触发一样。

您可以查看此示例http://jsbin.com/iwapi3,它说明了使用不带括号的版本时会发生什么。等待一段时间,checkEdge()呼叫计数器每 3 秒增加 7。您还会注意到,在某些情况下,动画部分起作用,并且一些 div 被移回列表的末尾(有时)。

一段时间后单击按钮并观察带有大括号的版本在运行几次后如何整理混乱(但现在正确的颜色顺序当然是混乱的)。checkEdge()每个动画只调用一次。(点击按钮后不久,您将获得另一个 +7,因为一些回调仍在处理中)

于 2009-11-18T10:09:11.143 回答
0

JavaScript 执行不会等到您的 animate 函数的 3000 毫秒用完。它启动 animate 函数,但随后(在 0-1 毫秒后)将继续执行您的 checkEdge() 函数。您不会检查您可能想要的 checkEdge() 中的状态。

为了防止这种情况,您应该将您的 checkEdge() 函数添加为 animate 函数的回调,该函数将在 3000 毫秒之后执行它。

试试这个:

$('.box').animate({'left' : "-=100px"}, 3000, 'linear', checkEdge);
于 2009-11-18T08:41:05.713 回答