Detectando quando o usuário rola para a parte inferior da div com jQuery

218

Eu tenho uma caixa de div (chamada de fluxo) com uma quantidade variável de conteúdo dentro. O estouro da caixa div está definido como automático.

Agora, o que estou tentando fazer é que, quando o uso rolar para a parte inferior desta caixa DIV, carregar mais conteúdo na página, eu sei como fazer isso (carregar o conteúdo), mas não sei como detectar quando o usuário rolou para a parte inferior da tag div? Se eu quisesse fazer isso por toda a página, pegaria .sollollTop e subtrairia isso de .height.

Mas parece que não consigo fazer isso aqui?

Eu tentei tirar .scrollTop do fluxo e, em seguida, agrupar todo o conteúdo dentro de uma div chamada inner, mas se eu pegar a innerHeight of flux, ela retornará 564px (a div está definida como 500 como altura) e a altura de 'innner' retorna 1064 e a barra de rolagem, quando na parte inferior da div diz 564.

O que eu posso fazer?

Eax
fonte

Respostas:

420

Existem algumas propriedades / métodos que você pode usar:

$().scrollTop()//how much has been scrolled
$().innerHeight()// inner height of the element
DOMElement.scrollHeight//height of the content of the element

Assim, você pode pegar a soma das duas primeiras propriedades e, quando é igual à última propriedade, chegou ao fim:

jQuery(function($) {
    $('#flux').on('scroll', function() {
        if($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) {
            alert('end reached');
        }
    })
});

http://jsfiddle.net/doktormolle/w7X9N/

Edit: Eu atualizei 'bind' para 'on' conforme:

A partir do jQuery 1.7, o método .on () é o método preferido para anexar manipuladores de eventos a um documento.

Dr.Molle
fonte
2
Ele fará a ligação quando o DOM estiver pronto para garantir que o # flux-element já esteja disponível.
Dr.Molle
1
você deve atualizar você responder usando ON em vez de ligamento, ligação é depreciado em favor do On
ncubica
34
Nota: Quando um usuário está usando os níveis de zoom no navegador, isso pode não funcionar. O zoom faz innerHeight()com que o relatório seja decimal. No caso de um usuário diminuir o zoom, a soma scrollTop()e innerHeight()sempre será pelo menos uma fração menor que scrollHeight. Acabei adicionando uma zona de buffer de 20px. A condicional resultante foi if(el.scrollTop() + el.innerHeight() >= el[0].scrollHeight - 20)onde elé igual $(this).
Nick
1
Esta é a melhor resposta que já funcionou muito bem para mim. Obrigado
Ashish Yadav 02/02
1
Não está mais funcionando, você pode confirmar se por que ele não está funcionando, Graças
Umair Shah Yousafzai
50

Encontrei uma solução que, quando você rola a janela e o final de uma div mostrada na parte inferior, emite um alerta.

$(window).bind('scroll', function() {
    if($(window).scrollTop() >= $('.posts').offset().top + $('.posts').outerHeight() - window.innerHeight) {
        alert('end reached');
    }
});

Neste exemplo, se você rolar para baixo quando div ( .posts) terminar, fornecerá um alerta.

ehsan Aghaei
fonte
obrigado por isso, mas como posso fazer a div animar quando chegar ao fundo dessa div? Além disso, quando você rola para cima, detecta a parte superior dessa div e também anima. Assim como aqui neste site lazada.com.ph/apple o comportamento da barra lateral espero que possa me ajudar :)
Alyssa Reyes
Ele funciona como uma mágica, mas o problema que o alerta é executado duas vezes por isso, se você tem uma chamada de uma função dentro dele será executado duas vezes
Afaf
1
@ 1616 Eu tenho uma variável var running = falsedeclarada antes disso. Dentro do condicional, verifico. if(!running) { running = true; // and continue logic } Dessa forma, é chamado apenas uma vez! Quando da conclusão do AJAX, setrunning = false;
Jacob Raccuia
1
É sobre janela, mas a pergunta é sobre div.
Alexander Volkov
42

Embora a pergunta tenha sido feita há 5,5 anos, ainda é mais do que relevante no contexto atual de UI / UX. E eu gostaria de adicionar meus dois centavos.

var element = document.getElementById('flux');
if (element.scrollHeight - element.scrollTop === element.clientHeight)
    {
        // element is at the end of its scroll, load more content
    }

Fonte: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Determine_if_an_element_has_been_totally_scrolled

Alguns elementos não permitem rolar a altura total do elemento. Nesses casos, você pode usar:

var element = docuement.getElementById('flux');
if (element.offsetHeight + element.scrollTop === element.scrollHeight) {
  // element is at the end of its scroll, load more content
}
Pensando
fonte
2
Esta é a solução que você está procurando se não estiver usando o jQuery.
Petter Pettersson
Existe o manipulador de eventos?
Alexander Volkov
O onscroll do @AlexanderVolkov é o evento relacionado.
Pensando
9

Apenas uma observação adicional aqui, pois achei isso ao procurar uma solução para uma div fixa que eu quero rolar. Para o meu cenário, descobri que é preferível levar em consideração o preenchimento na div para que eu possa chegar exatamente ao final. Então, expandindo a resposta do Dr.Molle, adiciono o seguinte

$('#flux').bind('scroll', function() {
    var scrollPosition = $(this).scrollTop() + $(this).outerHeight();
    var divTotalHeight = $(this)[0].scrollHeight 
                          + parseInt($(this).css('padding-top'), 10) 
                          + parseInt($(this).css('padding-bottom'), 10)
                          + parseInt($(this).css('border-top-width'), 10)
                          + parseInt($(this).css('border-bottom-width'), 10);

    if( scrollPosition == divTotalHeight )
    {
      alert('end reached');
    }
  });

Isso fornecerá a localização precisa, incluindo preenchimento e bordas

Alexander Millar
fonte
7

isso funcionou para mim embora

$(window).scroll(function() {
  if ($(window).scrollTop() >= (($(document).height() - $(window).height()) - $('#divID').innerHeight())) {
    console.log('div reached');
  }
});
Ricardo Rivas
fonte
3

Se você precisar usar isso em uma div que esteja excedente-y como oculta ou rolagem, algo como isto pode ser o que você precisa.

if ($('#element').prop('scrollHeight') - $('#element').scrollTop() <= Math.ceil($('#element').height())) {
    at_bottom = true;
}

Eu descobri que o teto era necessário porque o prop scrollHeight parece arredondar, ou talvez algum outro motivo para desativá-lo em menos de 1.

Ganso
fonte
3

Se você não estiver usando a função Math.round (), a solução sugerida pelo Dr.Molle não funcionará em alguns casos quando uma janela do navegador tiver um zoom.

Por exemplo $ (this) .scrollTop () + $ (this) .innerHeight () = 600

$ (this) [0] .scrollHeight yield = 599.99998

600> = 599.99998 falha.

Aqui está o código correto:

jQuery(function($) {
    $('#flux').on('scroll', function() {
        if(Math.round($(this).scrollTop() + $(this).innerHeight(), 10) >= Math.round($(this)[0].scrollHeight, 10)) {
            alert('end reached');
        }
    })
});

Você também pode adicionar alguns pixels extras de margem se não precisar de uma condição estrita

var margin = 4

jQuery(function($) {
    $('#flux').on('scroll', function() {
        if(Math.round($(this).scrollTop() + $(this).innerHeight(), 10) >= Math.round($(this)[0].scrollHeight, 10) - margin) {
            alert('end reached');
        }
    })
});
Павел Гавриленко
fonte
2

No uso simples do DOM, você pode verificar a condição

element.scrollTop + element.clientHeight == element.scrollHeight

se for verdade, você chegou ao fim.

Louay Alosh
fonte
1

Se alguém obtiver o scrollHeightas undefined, selecione o primeiro subelemento dos elementos:mob_top_menu[0].scrollHeight

Starwave
fonte
1

não tenho certeza se é alguma ajuda, mas é assim que eu faço.

Eu tenho um painel de índice maior que a janela e deixo rolar até o final desse índice. Então eu coloco na posição correta. O processo é revertido quando você rolar para o topo da página.

Saudações.

<style type="text/css">
    .fixed_Bot {    
            position: fixed;     
            bottom: 24px;    
        }     
</style>

<script type="text/javascript">
    $(document).ready(function () {
        var sidebarheight = $('#index').height();
        var windowheight = $(window).height();


        $(window).scroll(function () {
            var scrollTop = $(window).scrollTop();

            if (scrollTop >= sidebarheight - windowheight){
                $('#index').addClass('fixed_Bot');
            }
            else {
                $('#index').removeClass('fixed_Bot');
            }                   
        });
    });

</script>
Israel Chapa
fonte
1

Embora isso tenha sido perguntado há quase 6 anos, tópico ainda quente no design de UX, aqui está um trecho de demonstração, se algum novato quiser usar

$(function() {

  /* this is only for demonstration purpose */
  var t = $('.posts').html(),
    c = 1,
    scroll_enabled = true;

  function load_ajax() {

    /* call ajax here... on success enable scroll  */
    $('.posts').append('<h4>' + (++c) + ' </h4>' + t);

    /*again enable loading on scroll... */
    scroll_enabled = true;

  }


  $(window).bind('scroll', function() {
    if (scroll_enabled) {

      /* if 90% scrolled */
    if($(window).scrollTop() >= ($('.posts').offset().top + $('.posts').outerHeight()-window.innerHeight)*0.9) {

        /* load ajax content */
        scroll_enabled = false;  
        load_ajax();
      }

    }

  });

});
h4 {
  color: red;
  font-size: 36px;
  background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<div class="posts">
  Lorem ipsum dolor sit amet  Consectetuer augue nibh lacus at <br> Pretium Donec felis dolor penatibus <br> Phasellus consequat Vivamus dui lacinia <br> Ornare nonummy laoreet lacus Donec <br> Ut ut libero Curabitur id <br> Dui pretium hendrerit
  sapien Pellentesque <br> Lorem ipsum dolor sit amet <br> Consectetuer augue nibh lacus at <br> Pretium Donec felis dolor penatibus <br> Phasellus consequat Vivamus dui lacinia <br> Ornare nonummy laoreet lacus Donec <br> Ut ut libero Curabitur id <br>  Dui pretium hendrerit sapien Pellentesque <br> Lorem ipsum dolor sit amet <br> Consectetuer augue nibh lacus at <br> Pretium Donec felis dolor penatibus <br> Phasellus consequat Vivamus dui lacinia <br> Ornare nonummy laoreet lacus Donec <br> Ut ut
  libero Curabitur id <br> Dui pretium hendrerit sapien Pellentesque <br> Lorem ipsum dolor sit amet <br> Consectetuer augue nibh lacus at <br> Pretium Donec felis dolor penatibus <br> Phasellus consequat Vivamus dui lacinia <br> Ornare nonummy laoreet
  lacus Donec <br> Ut ut libero Curabitur id <br> Dui pretium hendrerit sapien Pellentesque
</div>

Akshay Hegde
fonte
0

Pessoal, essa é a solução para o problema do zoom, ele funciona com todos os níveis de zoom, caso você precise:

if ( Math.abs(elem.offset().top) + elem.height() + elem.offset().top >= elem.outerHeight() ) {
                    console.log("bottom");
                    // We're at the bottom!
                }
            });
        }
Liad Livnat
fonte
0
$(window).on("scroll", function() {
    //get height of the (browser) window aka viewport
    var scrollHeight = $(document).height();
    // get height of the document 
    var scrollPosition = $(window).height() + $(window).scrollTop();
    if ((scrollHeight - scrollPosition) / scrollHeight === 0) {
        // code to run when scroll to bottom of the page
    }
});

Este é o código no github.

aki_sud
fonte
-1

Aqui está outra versão.

O código da tecla é a função scroller (), que recebe a entrada como a altura da div que contém a seção de rolagem, usando overflow: scroll. Ele se aproxima de 5px a partir do topo ou 10px a partir do fundo, como na parte superior ou inferior. Caso contrário, é muito sensível. Parece que 10px é o mínimo. Você verá que ele adiciona 10 à altura da div para obter a altura inferior. Presumo que 5px possa funcionar, não testei extensivamente. YMMV. scrollHeight retorna a altura da área de rolagem interna, não a altura exibida da div, que neste caso é 400px.

<?php

$scrolling_area_height=400;
echo '
<script type="text/javascript">
          function scroller(ourheight) {
            var ourtop=document.getElementById(\'scrolling_area\').scrollTop;
            if (ourtop > (ourheight-\''.($scrolling_area_height+10).'\')) {
                alert(\'at the bottom; ourtop:\'+ourtop+\' ourheight:\'+ourheight);
            }
            if (ourtop <= (5)) {
                alert(\'Reached the top\');
            }
          }
</script>

<style type="text/css">
.scroller { 
            display:block;
            float:left;
            top:10px;
            left:10px;
            height:'.$scrolling_area_height.';
            border:1px solid red;
            width:200px;
            overflow:scroll; 
        }
</style>

$content="your content here";

<div id="scrolling_area" class="scroller">
onscroll="var ourheight=document.getElementById(\'scrolling_area\').scrollHeight;
        scroller(ourheight);"
        >'.$content.'
</div>';

?>
John Ostrowick
fonte
1
-1 porque gerar código javascript + css a partir do php é uma prática ruim (difícil de manter, sem reutilização, sem otimizações de site etc.). Além disso, como apontado por @Alexander Millar, o deslocamento de 10px pode ser corrigido levando em consideração o preenchimento. Qualquer um que considera usando este código deve pensar duas vezes ...
Kapitein Witbaard