Проверьте, прокрутил ли пользователь до дна

575

Я создаю систему разбиения на страницы (вроде Facebook), где контент загружается, когда пользователь прокручивается вниз. Я предполагаю, что лучший способ сделать это - найти, когда пользователь находится в нижней части страницы, и запустить запрос ajax для загрузки большего количества сообщений.

Единственная проблема заключается в том, что я не знаю, как проверить, прокручивается ли пользователь в нижней части страницы с помощью jQuery. Любые идеи?

Мне нужно найти способ проверить, когда пользователь прокручивается в нижней части страницы с помощью jQuery.

Показать ещё 1 комментарий
Теги:
scroll
pagination

21 ответ

910
Лучший ответ

Используйте .scroll() событие window, например:

$(window).scroll(function() {
   if($(window).scrollTop() + $(window).height() == $(document).height()) {
       alert("bottom!");
   }
});

Вы можете протестировать его здесь, это занимает верхний прокрутки окна, поэтому, насколько он прокручивается вниз, добавляет высоту видимого окно и проверяет, соответствует ли это высоте общего содержимого (document). Если вы хотите вместо этого проверить, находится ли пользователь в нижней части, он выглядит примерно так:

$(window).scroll(function() {
   if($(window).scrollTop() + $(window).height() > $(document).height() - 100) {
       alert("near bottom!");
   }
});

Вы можете протестировать эту версию здесь, просто настройте этот 100 на любой пиксель снизу, на который вы хотите включить.

  • 30
    Как обычно, ты доберешься до меня. В любом случае, для OP, если у вас есть контейнер сообщений, используйте его идентификатор вместо «окна», также вы можете изменить последний .height () на scrollHeight
  • 10
    это прекрасно работает! но разве это не тяжело? на каждом свитке?
Показать ещё 28 комментариев
103

Ответ Nick Craver отлично работает, избавляет от проблемы, что значение $(document).height() зависит от браузера.

Чтобы он работал на всех браузерах, используйте эту функцию из James Padolsey:

function getDocHeight() {
    var D = document;
    return Math.max(
        D.body.scrollHeight, D.documentElement.scrollHeight,
        D.body.offsetHeight, D.documentElement.offsetHeight,
        D.body.clientHeight, D.documentElement.clientHeight
    );
}

вместо $(document).height(), так что конечный код:

$(window).scroll(function() {
       if($(window).scrollTop() + $(window).height() == getDocHeight()) {
           alert("bottom!");
       }
   });
  • 5
    Он обновил немного сжатой версией функции getDocHeight () {var D = document; return Math.max (D.body.scrollHeight, D.documentElement.scrollHeight, D.body.offsetHeight, D.documentElement.offsetHeight, D.body.clientHeight, D.documentElement.clientHeight); }
  • 0
    который предупреждает меня, когда я достигаю вершины, а не низа (Chrome).
62

Я не совсем уверен, почему это еще не опубликовано, но согласно документации из MDN, самый простой способ - использовать собственные свойства javascript:

element.scrollHeight - element.scrollTop === element.clientHeight

Возвращает true, когда вы находитесь в нижней части любого прокручиваемого элемента. Поэтому просто используя javascript:

element.addEventListener('scroll', function(event)
{
    var element = event.target;
    if (element.scrollHeight - element.scrollTop === element.clientHeight)
    {
        console.log('scrolled');
    }
});

scrollHeight имеют широкую поддержку в браузерах, то есть 8, чтобы быть более точными, а clientHeight и scrollTop поддерживаются всеми. Даже то есть 6. Это должно быть безопасным для браузера.

  • 1
    Обратите внимание, что в некоторых ситуациях это может быть не так. Firefox 47 сообщает textarea clientHeight как 239, тогда как вышеприведенное уравнение дает 253 при прокрутке вниз. Может быть, отступы / границы или что-то на это влияет? В любом случае, добавление некоторой комнаты для маневра не повредит, например, var isAtBottom = ( logField.scrollHeight - logField.scrollTop <= logField.clientHeight + 50 ); , Это полезно для автоматической прокрутки поля, только если оно уже внизу (поэтому пользователь может вручную просмотреть определенную часть журнала в реальном времени, не теряя своего места и т. Д.).
  • 0
    Я хотел бы добавить, что он может возвращать ложные отрицания, поскольку одна сторона может вернуть небольшое десятичное число, а другая сторона возвращает целое число (например, 200.181819304947 и 200 ). Я добавил Math.floor() чтобы помочь справиться с этим, но я не знаю, насколько это будет надежно.
Показать ещё 4 комментария
46

Для тех, кто использует решение Ник и получает повторные предупреждения/события, вы можете добавить строку кода выше примера предупреждения:

$(window).scroll(function() {
   if($(window).scrollTop() + $(window).height() > $(document).height() - 100) {
       $(window).unbind('scroll');
       alert("near bottom!");
   }
});

Это означает, что код будет срабатывать только в первый раз, когда вы находитесь в пределах 100 пикселей от нижней части документа. Он не будет повторяться, если вы прокрутите резервную копию, а затем отпустите, что может быть полезно или не может быть полезно в зависимости от того, для чего вы используете код Nick.

  • 1
    Я бы просто прокомментировал и сказал, где эта строка кода, поскольку она имеет отношение к чьему-либо ответу, но +1 для намерения!
  • 0
    Извините, я не мог (и все еще не могу) увидеть, как добавить комментарий к ответу (как я могу здесь)?
Показать ещё 4 комментария
38

В дополнение к превосходному принятому ответу от Nick Craver вы можете дросселировать событие прокрутки так, чтобы оно не запускалось так часто, таким образом увеличение производительности браузера:

var _throttleTimer = null;
var _throttleDelay = 100;
var $window = $(window);
var $document = $(document);

$document.ready(function () {

    $window
        .off('scroll', ScrollHandler)
        .on('scroll', ScrollHandler);

});

function ScrollHandler(e) {
    //throttle event:
    clearTimeout(_throttleTimer);
    _throttleTimer = setTimeout(function () {
        console.log('scroll');

        //do work
        if ($window.scrollTop() + $window.height() > $document.height() - 100) {
            alert("near bottom!");
        }

    }, _throttleDelay);
}
  • 0
    Вероятно, следует указать, что для этого требуется Underscore.js: underscorejs.org . Это очень хороший момент, хотя. Событие прокрутки должно быть практически всегда ограничено, чтобы избежать серьезных проблем с производительностью.
  • 34
    Приведенный выше код НЕ требует Underscore.js
Показать ещё 3 комментария
36

Ответ Nick Craver должен быть слегка изменен для работы с iOS 6 Safari Mobile и должен быть:

$(window).scroll(function() {
   if($(window).scrollTop() + window.innerHeight == $(document).height()) {
       alert("bottom!");
   }
});

Изменение $(window).height() на window.innerHeight должно выполняться, потому что, когда адресная строка скрыта, дополнительные 60 пикселей добавляются к высоте окна, но используя $(window).height() отражает не это изменение, а использование window.innerHeight делает.

Примечание. Свойство window.innerHeight также включает горизонтальную высоту полосы прокрутки (если она отображается), в отличие от $(window).height(), которая не будет включать горизонтальную высоту полосы прокрутки. Это не проблема в Mobile Safari, но может привести к неожиданному поведению в других браузерах или будущих версиях Mobile Safari. Изменение == до >= может исправить это для большинства распространенных случаев использования.

Подробнее о свойстве window.innerHeight здесь

  • 0
    window.innerHeight имеет больше смысла за то, что я пытался достичь, спасибо!
  • 0
    Как получить оставшуюся высоту после прокрутки?
17

Здесь довольно простой подход:

elm.onscroll = function() {
    if(elm.scrollTop + elm.clientHeight == elm.scrollHeight) //User has scrolled to the bottom of the element
}
14

Вот фрагмент кода, который поможет вам отладить ваш код, я протестировал вышеупомянутые ответы и обнаружил, что они ошибочны. Я тестировал следующие действия в Chrome, IE, Firefox, IPad (Safari). У меня нет других, чтобы проверить...

<script type="text/javascript">
   $(function() {
      $(window).scroll(function () {
         var docElement = $(document)[0].documentElement;
         var winElement = $(window)[0];

         if ((docElement.scrollHeight - winElement.innerHeight) == winElement.pageYOffset) {
            alert('bottom');
         }
      });
   });
</script>

Может быть более простое решение, но я остановился в точке, где IT WORKED

Если у вас все еще есть проблемы с некоторыми браузерами-изгоями, вот какой код вы можете отлаживать:

<script type="text/javascript">
   $(function() {
      $(window).scroll(function () {
         var docElement = $(document)[0].documentElement;
         var details = "";
         details += '<b>Document</b><br />';
         details += 'clientHeight:' + docElement.clientHeight + '<br />';
         details += 'clientTop:' + docElement.clientTop + '<br />';
         details += 'offsetHeight:' + docElement.offsetHeight + '<br />';
         details += 'offsetParent:' + (docElement.offsetParent == null) + '<br />';
         details += 'scrollHeight:' + docElement.scrollHeight + '<br />';
         details += 'scrollTop:' + docElement.scrollTop + '<br />';

         var winElement = $(window)[0];
         details += '<b>Window</b><br />';
         details += 'innerHeight:' + winElement.innerHeight + '<br />';
         details += 'outerHeight:' + winElement.outerHeight + '<br />';
         details += 'pageYOffset:' + winElement.pageYOffset + '<br />';
         details += 'screenTop:' + winElement.screenTop + '<br />';
         details += 'screenY:' + winElement.screenY + '<br />';
         details += 'scrollY:' + winElement.scrollY + '<br />';

         details += '<b>End of page</b><br />';
         details += 'Test:' + (docElement.scrollHeight - winElement.innerHeight) + '=' + winElement.pageYOffset + '<br />';
         details += 'End of Page? ';
         if ((docElement.scrollHeight - winElement.innerHeight) == winElement.pageYOffset) {
             details += 'YES';
         } else {
             details += 'NO';
         }

         $('#test').html(details);
      });
   });
</script>
<div id="test" style="position: fixed; left:0; top: 0; z-index: 9999; background-color: #FFFFFF;">

Надеюсь, это немного сэкономит время.

  • 0
    Лучший ответ для Vanilla JS, нет решения JQuery. Используйте var docElement = document.documentElement; var winElement = window
10
var elemScrolPosition = elem.scrollHeight - elem.scrollTop - elem.clientHeight;

Он вычисляет полосу прокрутки расстояния до нижней части элемента. Равно 0, если полоса прокрутки достигла дна.

  • 1
    Я сделал следующее и работал без нареканий. Благодарю. var shouldScroll = (elem.scrollHeight - elem.scrollTop - elem.clientHeight) == 0;
10

Пожалуйста, проверьте этот ответ

 window.onscroll = function(ev) {
    if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
       console.log("bottom");
    }
};

Вы можете сделать footerHeight - document.body.offsetHeight, чтобы увидеть, находитесь ли вы рядом с нижним колонтитулом или достигли нижнего колонтитула

8

Это мои два цента:

$('#container_element').scroll( function(){
        console.log($(this).scrollTop()+' + '+ $(this).height()+' = '+ ($(this).scrollTop() + $(this).height())   +' _ '+ $(this)[0].scrollHeight  );
        if($(this).scrollTop() + $(this).height() == $(this)[0].scrollHeight){
            console.log('bottom found');
        }
    });
5

Pure JS с кросс-браузер и debouncing (довольно хорошая производительность)

var CheckIfScrollBottom = debouncer(function() {
    if(getDocHeight() == getScrollXY()[1] + window.innerHeight) {
       console.log('Bottom!');
    }
},500);

document.addEventListener('scroll',CheckIfScrollBottom);

function debouncer(a,b,c){var d;return function(){var e=this,f=arguments,g=function(){d=null,c||a.apply(e,f)},h=c&&!d;clearTimeout(d),d=setTimeout(g,b),h&&a.apply(e,f)}}
function getScrollXY(){var a=0,b=0;return"number"==typeof window.pageYOffset?(b=window.pageYOffset,a=window.pageXOffset):document.body&&(document.body.scrollLeft||document.body.scrollTop)?(b=document.body.scrollTop,a=document.body.scrollLeft):document.documentElement&&(document.documentElement.scrollLeft||document.documentElement.scrollTop)&&(b=document.documentElement.scrollTop,a=document.documentElement.scrollLeft),[a,b]}
function getDocHeight(){var a=document;return Math.max(a.body.scrollHeight,a.documentElement.scrollHeight,a.body.offsetHeight,a.documentElement.offsetHeight,a.body.clientHeight,a.documentElement.clientHeight)}

Демо: http://jsbin.com/geherovena/edit?js,output

PS: Debouncer, getScrollXY, getDocHeight не написано мной

Я просто покажу, как его работа, И как я буду делать

  • 0
    Отлично. Проверено в Firefox и Chrome
2

Попробуйте это для условия соответствия, если прокрутить до нижнего конца

if ($(this)[0].scrollHeight - $(this).scrollTop() == 
    $(this).outerHeight()) {

    //code for your custom logic

}
2

Вы можете попробовать следующий код,

$("#dashboard-scroll").scroll(function(){
    var ele = document.getElementById('dashboard-scroll');
    if(ele.scrollHeight - ele.scrollTop === ele.clientHeight){
       console.log('at the bottom of the scroll');
    }
});
2

Nick отвечает на все вопросы, но у вас будут функции, которые повторяются при прокрутке или вообще не будут работать, если пользователь увеличил окно. Я придумал простое исправление только математике. Вокруг первой высоты и работает так же, как предполагалось.

    if (Math.round($(window).scrollTop()) + $(window).innerHeight() == $(document).height()){
    loadPagination();
    $(".go-up").css("display","block").show("slow");
}
1

Все эти решения не работают для меня в Firefox и Chrome, поэтому я использую пользовательские функции из Miles O'Keefe и meder omuraliev вот так:

function getDocHeight()
{
    var D = document;
    return Math.max(
        D.body.scrollHeight, D.documentElement.scrollHeight,
        D.body.offsetHeight, D.documentElement.offsetHeight,
        D.body.clientHeight, D.documentElement.clientHeight
    );
}

function getWindowSize()
{
  var myWidth = 0, myHeight = 0;
  if( typeof( window.innerWidth ) == 'number' ) {
    //Non-IE
    myWidth = window.innerWidth;
    myHeight = window.innerHeight;
  } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
    //IE 6+ in 'standards compliant mode'
    myWidth = document.documentElement.clientWidth;
    myHeight = document.documentElement.clientHeight;
  } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
    //IE 4 compatible
    myWidth = document.body.clientWidth;
    myHeight = document.body.clientHeight;
  }
  return [myWidth, myHeight];
}

$(window).scroll(function()
{
    if($(window).scrollTop() + getWindowSize()[1] == getDocHeight())
    {
        alert("bottom!");
    }
});
1

Позвольте мне показать соответствие без JQuery. Простая функция JS:

function isVisible(elem) {
  var coords = elem.getBoundingClientRect();
  var topVisible = coords.top > 0 && coords.top < 0;
  var bottomVisible = coords.bottom < shift && coords.bottom > 0;
  return topVisible || bottomVisible;
}

Короткий пример того, как его использовать:

var img = document.getElementById("pic1");
    if (isVisible(img)) { img.style.opacity = "1.00";  }
  • 3
    Это не отвечает на вопрос. Вопрос заключался в том, как определить, что пользователи прокручивали окно до самого дна. Ваш код проверяет, находится ли конкретный элемент в поле зрения.
0

Здесь мои два цента как принятый ответ не работали для меня.

var documentAtBottom = (document.documentElement.scrollTop + window.innerHeight) >= document.documentElement.scrollHeight;
0

Мое решение в простой JS:

let el=document.getElementById('el');
el.addEventListener('scroll', function (e) {
		if (el.scrollHeight - el.scrollTop - el.clientHeight<0) {
      console.log('Bottom')
    }
});
#el{
  width:300px;
  height:100px;
  overflow-y:scroll;
}
<div id="el">
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
</div>
0

Чтобы остановить повторное оповещение о ответе Ника.

ScrollActivate();

function ScrollActivate() {
    $(window).on("scroll", function () {
        if ($(window).scrollTop() + $(window).height() > $(document).height() - 100) {
            $(window).off("scroll");
            alert("near bottom!");
        }
    });
}
0

Я использовал @ddonone answear и добавил вызов Ajax.

$('#mydiv').on('scroll', function(){
  function infiniScroll(this);
});

function infiniScroll(mydiv){
console.log($(mydiv).scrollTop()+' + '+ $(mydiv).height()+' = '+ ($(mydiv).scrollTop() + $(mydiv).height())   +' _ '+ $(mydiv)[0].scrollHeight  );

if($(mydiv).scrollTop() + $(mydiv).height() == $(mydiv)[0].scrollHeight){
    console.log('bottom found');
    if(!$.active){ //if there is no ajax call active ( last ajax call waiting for results ) do again my ajax call
        myAjaxCall();
    }
}

}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню