Pergunta

Estou continuando um postagem anterior, mas pensei em abrir um novo tópico, pois é uma abordagem diferente e tem mais código real. De qualquer forma, estou tentando obter um loop infinito com o Divs rolando através de uma janela (a outra postagem tem uma imagem e o código abaixo funciona).

<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>

De qualquer forma, o problema é que eu posso fazer com que as caixas se movam para a esquerda, mas não consigo colocar a caixa principal para voltar ao final da linha quando corro a coisa toda. Quando eu executo cada função separadamente (usando o Firebug) -

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

Funciona muito bem. Quando os coloquei, eu só recebo um movimento contínuo da direita para a esquerda até que as caixas saem da tela, então deve ser como elas interagem. Espero que isso faça sentido (se não, salve o bloco de código acima como um arquivo HTML e execute -o em um navegador). Estou preso nisso por um tempo, então qualquer ajuda será incrível. Obrigado.

Foi útil?

Solução

Você precisa definir o retorno de chamada como este

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

checkEdge() não checkEdge

Verifique aqui uma solução de trabalho http://jsbin.com/uceqi (Basta copiar seu código colado)


Aqui, na verdade, faz a diferença se você deixar o aparelho para longe. A versão com aparelho é executada checkEdge() Uma vez por animação (para ser honesto na realidade, ele executa checkEdge Antes que a animação comece. o checkEdge()A função é chamada quando o $...animte(..) a declaração é alcançada mesmo antes animate() Ele próprio é executado. checkEdge faria com que a função fosse passada como parâmetro, normalmente o caminho correto a seguir).

A versão sem aparelho é executada checkEdge Uma vez para o número de elementos correspondentes ao seletor. Nesse caso, 6 vezes.

Então, tecnicamente falando, sua abordagem estaria correta, pois dispararia o retorno de chamada uma vez por elemento animado e DEPOIS a animação. Mas executando checkEdge Uma vez que isso obviamente não é o que o autor pretendia (verifique o loop sobre divs em checkEdge). E também causa atraso grave ao fazer um loop várias vezes sobre todos os divs

6divs animados -> 6x de retorno de chamada disparado -> Loops de retorno de chamada sobre todos os divs ==> 36x execução da função anônima em checkEdge()!!

Portanto, o problema real é que o retorno de chamada é demitido 6x e tudo ao mesmo tempo. Assim, temos uma condição de corrida e a animação estraga tudo. Como vários checkEdge() chama o trabalho simultaneamente para reposicionar os divs.

Mas você só percebe isso porque o animation-speed e o intervalo em setInterval (Shiftleft) são idênticos. Eles seriam diferentes ((intervalo +~ 1000ms)> velocidade da animação), então também funcionaria corretamente. Mas é claro que a animação não seria fluida. Como shitfLeft() dispararia 1s depois que a animação parou.

Você pode verificar esta amostra http://jsbin.com/iwapi3 que ilustra o que acontece quando use a versão sem aparelho. Espere por algum tempo e o balcão para checkEdge() As chamadas aumentam em 7 a cada 3s. Você também notará que, em alguns casos, a animação funciona parcialmente e algumas divs são transferidas de volta ao final da lista (às vezes).

Depois de algum tempo, clique no botão e observe como a versão com aparelho resolve a bagunça após algumas execuções (mas agora a ordem correta da cor é obviamente bagunçada). E apenas ligações checkEdge() Uma vez por animação. (Logo após pressionar o botão, você receberá outros +7, pois alguns retornos de chamada ainda estão no tubo)

Outras dicas

A execução do JavaScript não espera até que os 3000 ms de sua função animada sejam gastos. Ele inicia a função animada, mas então (após 0-1 ms) passará para a função checkedge (). Você não verifica o estado em checkedge () que pode querer.

Para evitar isso, você deve adicionar sua função checkEdge () como retorno de chamada à função animada, que o executará exatamente após esses 3000ms.

Experimente isso:

$('.box').animate({'left' : "-=100px"}, 3000, 'linear', checkEdge);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top