Détection lorsque l'utilisateur fait défiler vers le bas de div avec jQuery

219

J'ai une boîte div (appelée flux) avec une quantité variable de contenu à l'intérieur. Cette divbox a un débordement réglé sur auto.

Maintenant, ce que j'essaie de faire, c'est que lorsque l'utilisation défile vers le bas de cette boîte DIV, charge plus de contenu dans la page, je sais comment faire (charger le contenu) mais je ne sais pas comment détecter quand l'utilisateur a fait défiler vers le bas de la balise div? Si je voulais le faire pour la page entière, je prendrais .scrollTop et le soustraisais de .height.

Mais je n'arrive pas à faire ça ici?

J'ai essayé de prendre .scrollTop de flux, puis d'envelopper tout le contenu à l'intérieur d'un div appelé inner, mais si je prends la innerHeight du flux, il renvoie 564px (le div est défini sur 500 comme hauteur) et la hauteur de 'innner' il renvoie 1064, et le scrolltop, quand au bas de la div dit 564.

Que puis-je faire?

Eax
la source

Réponses:

421

Vous pouvez utiliser certaines propriétés / méthodes:

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

Vous pouvez donc prendre la somme des deux premières propriétés, et lorsqu'elle est égale à la dernière propriété, vous avez atteint la fin:

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

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

Edit: j'ai mis à jour 'bind' en 'on' selon:

Depuis jQuery 1.7, la méthode .on () est la méthode préférée pour attacher des gestionnaires d'événements à un document.

Dr.Molle
la source
2
Il fera la liaison lorsque le DOM sera prêt pour être sûr que l'élément # flux est déjà disponible.
Dr.Molle
1
vous devez mettre à jour votre réponse en utilisant ON au lieu de bind, bind est déconseillé en faveur de On
ncubica
34
Remarque: Lorsqu'un utilisateur utilise des niveaux de zoom sur son navigateur, cela peut ne pas fonctionner. Le zoom fait innerHeight()rapporter les décimales. Dans le cas d'un utilisateur effectuant un zoom arrière, la somme de scrollTop()et innerHeight()sera toujours inférieure d'au moins une fraction scrollHeight. J'ai fini par ajouter une zone tampon de 20 pixels. Le conditionnel résultant était if(el.scrollTop() + el.innerHeight() >= el[0].scrollHeight - 20)elégal à égal $(this).
Nick
1
C'est la meilleure réponse de tous les temps qui a très bien fonctionné pour moi. Merci
Ashish Yadav
1
Cela ne fonctionne plus, pouvez-vous confirmer pourquoi cela ne fonctionne pas, merci
Umair Shah Yousafzai
50

J'ai trouvé une solution qui lorsque vous faites défiler votre fenêtre et à la fin d'une div affichée en bas vous donne une alerte.

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

Dans cet exemple, si vous faites défiler vers le bas lorsque div ( .posts) a terminé, vous recevrez une alerte.

ehsan Aghaei
la source
merci pour cela mais comment puis-je faire animer le div quand il atteint le bas de ce div? aussi lorsque vous faites défiler vers le haut, détectez le haut de ce div puis animez également. Tout comme ici sur ce site lazada.com.ph/apple le comportement de la barre latérale J'espère que vous pourrez m'aider :)
Alyssa Reyes
Cela fonctionne comme par magie, mais le problème est que l'alerte est exécutée deux fois, donc si vous avez un appel d'une fonction à l'intérieur, elle sera exécutée deux fois
Afaf
1
@ 1616 J'ai une variable var running = falsedéclarée avant cela. A l'intérieur du conditionnel, je vérifie De if(!running) { running = true; // and continue logic } cette façon, il n'est appelé qu'une seule fois! Quand l'AJAX se termine, setrunning = false;
Jacob Raccuia
1
Il s'agit de fenêtre, mais la question porte sur div.
Alexander Volkov
42

Bien que la question ait été posée il y a 5,5 ans, elle est toujours plus que pertinente dans le contexte UI / UX d'aujourd'hui. Et je voudrais ajouter mes deux cents.

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

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

Certains éléments ne vous permettent pas de faire défiler toute la hauteur de l'élément. Dans ces cas, vous pouvez utiliser:

var element = docuement.getElementById('flux');
if (element.offsetHeight + element.scrollTop === element.scrollHeight) {
  // element is at the end of its scroll, load more content
}
En pensant
la source
2
C'est la solution que vous recherchez si vous n'utilisez pas jQuery.
Petter Pettersson
Il y a le gestionnaire d'événements?
Alexander Volkov
@AlexanderVolkov onscroll est l'événement connexe.
Réflexion du
9

Juste une note supplémentaire ici car j'ai trouvé cela lorsque je cherche une solution pour un div fixe que je veux faire défiler. Pour mon scénario, j'ai trouvé qu'il est préférable de prendre en compte le rembourrage sur le div afin que je puisse atteindre la fin exactement. Donc, en développant la réponse de @ Dr.Molle, j'ajoute ce qui suit

$('#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');
    }
  });

Cela vous donnera l'emplacement précis, y compris le rembourrage et les bordures

Alexander Millar
la source
7

cela a bien fonctionné pour moi

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

Si vous devez utiliser ceci sur un div qui a overflow-y comme caché ou scroll, quelque chose comme ça peut être ce dont vous avez besoin.

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

J'ai trouvé que le plafond était nécessaire car l'hélice scrollHeight semble arrondir, ou peut-être une autre raison qui fait que cela est désactivé de moins de 1.

OIE
la source
3

Si vous n'utilisez pas la fonction Math.round (), la solution suggérée par Dr.Molle ne fonctionnera pas dans certains cas lorsqu'une fenêtre de navigateur a un zoom.

Par exemple $ (this) .scrollTop () + $ (this) .innerHeight () = 600

$ (this) [0] .scrollHeight rendements = 599,99998

600> = 599,99998 échoue.

Voici le bon code:

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

Vous pouvez également ajouter des pixels de marge supplémentaires si vous n'avez pas besoin d'une condition stricte

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');
        }
    })
});
Павел Гавриленко
la source
2

Dans une utilisation DOM simple, vous pouvez vérifier la condition

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

si c'est vrai, alors vous avez atteint la fin.

Louay Alosh
la source
1

Si quelqu'un obtient scrollHeightas undefined, sélectionnez le 1er sous-élément des éléments:mob_top_menu[0].scrollHeight

Starwave
la source
1

Je ne sais pas si c'est de l'aide, mais c'est comme ça que je le fais.

J'ai un panneau d'index plus grand que la fenêtre et je le laisse défiler jusqu'à la fin de cet index. Ensuite, je le fixe en position. Le processus est inversé une fois que vous faites défiler vers le haut de la page.

Cordialement.

<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>
Israël Chapa
la source
1

Bien que cela ait été demandé il y a près de 6 ans, il y a encore un sujet brûlant dans la conception UX, voici un extrait de démo si un débutant voulait utiliser

$(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
la source
0

Les gars, c'est la solution au problème de zoom, il fonctionne avec tous les niveaux de zoom, au cas où vous en auriez besoin:

if ( Math.abs(elem.offset().top) + elem.height() + elem.offset().top >= elem.outerHeight() ) {
                    console.log("bottom");
                    // We're at the bottom!
                }
            });
        }
Liad Livnat
la source
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
    }
});

C'est le code sur github.

aki_sud
la source
-1

Voici une autre version.

Le code clé est la fonction scroller () qui prend la hauteur de la div contenant la section de défilement, en utilisant overflow: scroll. Il se rapproche de 5 pixels du haut ou de 10 pixels du bas comme en haut ou en bas. Sinon, c'est trop sensible. Il semble que 10px soit à peu près le minimum. Vous verrez qu'il ajoute 10 à la hauteur div pour obtenir la hauteur inférieure. Je suppose que 5px pourrait fonctionner, je n'ai pas testé intensivement. YMMV. scrollHeight renvoie la hauteur de la zone de défilement interne, pas la hauteur affichée du div, qui dans ce cas est 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
la source
1
-1 parce que générer du code javascript + css à partir de php est une mauvaise pratique (difficile à maintenir, pas de réutilisabilité, pas d'optimisation de site Web, etc.) De plus, comme l'a souligné @Alexander Millar, le décalage de 10 pixels peut être corrigé en tenant compte du remplissage. Quiconque envisage d'utiliser ce code devrait réfléchir à deux fois ...
Kapitein Witbaard