непрерывный цикл с div и jquery - PullRequest
3 голосов
/ 18 ноября 2009

Я продолжаю предыдущее сообщение , но я думал, что открою новую ветку, так как она использует другой подход и содержит более актуальный код. Во всяком случае, я пытаюсь заставить бесконечный цикл работать с прокруткой 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>

В любом случае, проблема в том, что я могу заставить ящики перемещаться влево, но я не могу заставить ведущий ящик возвращаться к концу строки, когда я запускаю все это. Когда я запускаю каждую функцию отдельно (используя firebug) -

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

Отлично работает. Когда я собираю их вместе, я просто получаю непрерывное движение справа налево, пока прямоугольники не покинут экран, поэтому, должно быть, они взаимодействуют друг с другом. Я надеюсь, что это имеет смысл (если нет, сохраните приведенный выше блок кода в виде файла HTML и запустите его в браузере). Я застрял на этом некоторое время, поэтому любая помощь будет потрясающей. Спасибо.

Ответы [ 2 ]

4 голосов
/ 18 ноября 2009

Вы должны установить обратный вызов, как это

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

checkEdge() не checkEdge

Проверьте здесь для рабочего решения http://jsbin.com/uceqi (просто скопируйте вставленный код)


Здесь на самом деле имеет значение, если вы оставите скобки в стороне. Версия с фигурными скобками выполняется checkEdge() один раз за анимацию (если честно, в действительности она выполняет checkEdge ДО запуска анимации . Функция checkEdge() вызывается, когда оператор $...animte(..) достигнут еще до animate() сам выполняется. checkEdge приведет к тому, что функция будет передана в качестве параметра, обычно это правильный путь).

Версия без фигурных скобок выполняется checkEdge один раз для количества элементов, соответствующих селектору. В этом случае 6 раз.

С технической точки зрения, ваш подход будет правильным, так как он будет вызывать обратный вызов один раз для каждого анимированного элемента и ПОСЛЕ анимации. Но выполнение checkEdge, как только это, очевидно, не то, что задумал автор (проверьте loop над div в checkEdge). А также вызывает серьезное отставание, когда вы повторяете несколько раз по всем div

6divs анимация -> 6x обратный вызов срабатывает -> цикл обратного вызова по всем div ==> 36x выполнение анонимной функции в checkEdge() !!

Таким образом, настоящая проблема заключается в том, что обратный вызов запускается 6 раз и все одновременно. Таким образом, у нас есть состояние гонки, и анимация испортилась. Поскольку несколько checkEdge() вызовов одновременно работают над изменением положения div.

Но вы заметите это только потому, что animation-speed и интервал в setInterval (shiftLeft) идентичны. Будут ли они отличаться ((интервал + ~ 1000 мс)> скорость анимации), то это будет работать правильно. Но, конечно, анимация не будет плавной. Как shitfLeft() будет срабатывать 1 с после остановки анимации.

Вы можете проверить этот пример http://jsbin.com/iwapi3, который иллюстрирует, что происходит при использовании версии без фигурных скобок. Подождите некоторое время, и счетчик checkEdge() вызовов увеличивается на 7 каждые 3 с. Вы также заметите, что в некоторых случаях анимация частично работает, а некоторые элементы div иногда возвращаются в конец списка.

Через некоторое время нажмите кнопку и посмотрите, как версия с фигурными скобками разбирает беспорядок после нескольких запусков (но теперь, конечно, неправильный порядок цвета, конечно, испорчен). И только вызывает checkEdge() один раз за анимацию. (Вскоре после нажатия кнопки вы получите еще один +7, так как некоторые обратные вызовы все еще находятся в канале)

0 голосов
/ 18 ноября 2009

Выполнение JavaScript не ждет, пока не будут потрачены 3000 мсек вашей анимационной функции. Он запускает функцию animate, но затем (через 0-1 мс) переходит к вашей функции checkEdge (). Вы не проверяете состояние в checkEdge (), которое хотите.

Чтобы предотвратить это, вы должны добавить функцию checkEdge () в качестве функции обратного вызова для функции animate, которая выполнит ее точно после этих 3000 мс.

Попробуйте это:

$('.box').animate({'left' : "-=100px"}, 3000, 'linear', checkEdge);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...