检查用户是否已滚动到底部


667

我正在创建一个分页系统(类似于Facebook),当用户滚动到底部时会加载内容。我想最好的方法是找到用户何时位于页面底部,并运行ajax查询以加载更多帖子。

唯一的问题是我不知道如何使用jQuery检查用户是否已滚动到页面底部。有任何想法吗?

我需要找到一种方法来检查用户何时使用jQuery滚动到页面底部。


很好笑,当我滚动到底部时,我试图弄清楚正在调用哪个函数,因此可以阻止这种令人讨厌的“功能”。
endolith '18

对于React.js解决方案,此链接可能会有所帮助:stackoverflow.com/a/53158893/4265546
raksheetbhat

Answers:


1023

.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为要触发的底部像素即可。


32
和往常一样,你到我那里去。无论如何,对于OP,如果您有一个帖子容器,请使用其ID代替“ window”,而且,您可能想将最后一个.height()更改为scrollHeight
Christian

4
Firefox调用alert(“ bottom!”); 很多次(适用于铬和野生动物园)
Marco Matarazzi 2012年

3
这有点像是越野车,如果您执行console.log()而不是提醒操作,有时会重复执行该命令。
尔根·保罗(

19
@KevinVella城很好地结合起来是下划线实用程序_.debounce()以此来防止它射击直至用户停止滚动- underscorejs.org/#debounce -
JohnnyFaldo

3
@NickCraver有可用的纯js实现吗?
Dewsworld

116

尼克·克雷弗(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!");
       }
   });

6
他已使用稍微压缩的版本函数getDocHeight()更新了内容[var D = document; 返回Math.max(D.body.scrollHeight,D.documentElement.scrollHeight,D.body.offsetHeight,D.documentElement.offsetHeight,D.body.clientHeight,D.documentElement.clientHeight); }
Drew

当我到达顶部而不是底部(Chrome)时会提醒我。
Damien Roche

最好使用min而不是来代替max,尤其是在有余量的情况下,以避免意外阻止用户滚动到您认为的页面底部。
所罗门·乌科

103

我不确定为什么还没有发布,但是根据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在浏览器的广泛支持,从IE 8更精确,同时clientHeightscrollTop都受到大家的支持。即使是6.也应该是跨浏览器安全的。


1
请注意,在某些情况下可能并非如此。Firefox 47将textarea clientHeight报告为239,而当滚动到底部时,上述公式给出253。也许填充/边框或其他因素正在影响它?无论哪种方式,添加一些摆动空间都不会造成伤害,例如var isAtBottom = ( logField.scrollHeight - logField.scrollTop <= logField.clientHeight + 50 );。仅当字段已经在底部时,这才对自动滚动字段很有用(因此用户可以手动检查实时日志的特定部分而不会丢失其位置,等等)。
Beejor

我要补充一点,因为一侧可能返回一个小数,而另一侧则返回一个整数(例如200.181819304947200),因此它可能返回假阴性。我添加了一个Math.floor()帮助解决该问题的方法,但我不知道这样做的可靠性。
汉娜

1
对我来说,这不适用于跨浏览器。与Firefox相比,我在chrome上获得了完全不同的结果。
塔德吉

1
我在<body>元素上尝试过此操作,当浏览器滚动到顶部而不是底部时,这会触发。
克里斯·索博列夫斯基

10
Math.abs(element.scrollHeight - element.scrollTop - element.clientHeight) <= 3.0(将3.0替换为您认为适合您的情况的像素公差)。之所以这样,是因为(A)clientHeightscrollTopclientHeight都经过四舍五入,如果全部对齐,则可能会导致3px错误;(B)用户几乎看不到3像素,因此用户可能会认为您的网站出了点问题当它们“思考”时,它们实际上位于页面的底部,而实际上它们不在页面的底部;并且(C)某些设备(尤其是无鼠标设备)在滚动时可能具有奇怪的行为。
杰克·吉芬

50

对于使用尼克解决方案并获得重复警报/事件触发的用户,您可以在警报示例上方添加一行代码:

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

这意味着该代码只会在您第一次位于文档底部100px以内时触发。如果向上滚动然后向下滚动,则不会重复,这可能有用也可能不会有用,具体取决于您使用Nick的代码的用途。


1
我只想发表评论,说那行代码在哪里,因为它与其他人的答案相关,但意图是+1!
Nate-Wilkins

抱歉,我无法(仍然无法)看到如何在答案中添加评论(就像我在这里可以看到的那样)?
蒂姆·卡尔

是的,除非获得更多代表,否则新用户无法在帖子中添加评论。
Nate-Wilkins

如果您可以放一个不同的东西(如果该东西测试您希望脚本进行的更改是否存在),则说第一个,例如说一个已应用于div的类。如果已经运行,则第二个嵌套如果不运行则嵌套。
1934286

如何选择特定的div ID而不是整个窗口?
詹姆斯·史密斯

40

除了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);
}

应该指出的是,这需要Underscore.js:underscorejs.org。不过,这是一个很好的观点。滚动事件几乎应该总是被限制以避免严重的性能问题。
裘德·奥斯本

也许只是我自己,它可以使用一些基准测试,但是我不喜欢在每个滚动事件上调用clearTimeout和setTimeout的想法。我将发出1 setTimeout并在该处理程序中添加一些防护措施。这可能只是微优化(如果有的话)。
绝望的鬼脸2013年

这真是一个很好的补充!我可以想到进一步的改进。当前,如果用户继续滚动,检查高度的功能将无法运行。如果这是一个问题(例如,您希望在用户向下滚动一半时触发该函数,而不管他们是否继续滚动),则可以轻松地确保该函数实际上已被调用,同时在选定的时间间隔内仍禁止多次调用。这里是要说明的要点。gist.github.com/datacarl/7029558
datacarl 2013年

什么?调用机械负载以防止进行简单计算?我根本看不到效率如何
Rambatino

37

尼克·克雷弗(Nick Craver)的答案需要稍做修改才能在iOS 6 Safari Mobile上运行,并且应为:

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

更改$(窗口).height()window.innerHeight应该做的事,因为当地址栏被隐藏额外的60像素被添加到窗口的高度,但使用$(window).height()没有反映这种变化,同时使用window.innerHeight呢。

注意:该window.innerHeight属性还包括水平滚动条的高度(如果已渲染),与之不同的是,该属性$(window).height()将不包括水平滚动条的高度。在Mobile Safari中这不是问题,但可能导致其他浏览器或Mobile Safari的未来版本中出现意外行为。更改==>=可以解决大多数常见用例的问题。

此处详细了解该window.innerHeight物业


window.innerHeight对于我要完成的工作更加有意义!
Amir5000

滚动后如何获得剩余高度?
OPV

20

这是一个相当简单的方法

const didScrollToBottom = elm.scrollTop + elm.clientHeight == elm.scrollHeight

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

elm从ie中检索到的元素在哪里document.getElementById


17

这是一段代码,可以帮助您调试代码,我测试了以上答案,发现它们有故障。我已经在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>

可能有一个更简单的解决方案,但我停在了 下来

如果某些流氓浏览器仍存在问题,请使用以下代码来调试:

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

我希望这可以节省一些时间。


Vanilla js的最佳答案,没有jQuery解决方案。使用var docElement = document.documentElement; var winElement = window
jperelli

这是2019年。winElement.pageYOffset您也可以使用winElement.scrollY
Noel Abrahams

15

请检查此答案

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

您可以footerHeight - document.body.offsetHeight查看是在页脚附近还是到达页脚


12
var elemScrolPosition = elem.scrollHeight - elem.scrollTop - elem.clientHeight;

它计算到元素底部的距离滚动条。如果滚动条到达底部,则等于0。


1
我做了以下工作,工作无懈可击。谢谢。var shouldScroll =(elem.scrollHeight-elem.scrollTop-elem.clientHeight)== 0;
jiminssy

11

这是我的两分钱:

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

尝试使用您的解决方案,它可以正常工作,但是在元素具有填充的情况下-它无法工作,因为它计算元素的纯净高度,不包括填充,可以解决此问题,我将其更改为$(this).scrollTop() + $(this).height() == $(this)[0].scrollHeight=>$(this).scrollTop() + $(this).outerHeight(true) >= $(this)[0].scrollHeight
Taras Chernata

6

具有跨浏览器反跳功能的 纯JS (相当不错的性能

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,输出

PS: ,,Debouncer 不是我写的getScrollXYgetDocHeight

我只是展示它的工作方式,以及我将如何做


完善。在Firefox和Chrome中进行了测试
Erlisar Vasquez

我收到以下错误:期望3个参数,但得到2个。未提供参数'c'。
清醒的

6

我的普通js解决方案:

let el=document.getElementById('el');
el.addEventListener('scroll', function(e) {
    if (this.scrollHeight - this.scrollTop - this.clientHeight<=0) {
        alert('Bottom');
    }
});
#el{
  width:400px;
  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>


4

如果滚动到最底端,请尝试此匹配条件

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

    //code for your custom logic

}

3

尼克回答得很好,但是您将拥有在滚动时会重复其自身的功能,或者如果用户缩放了窗口则根本无法使用。我想出了一个简单的修复方法,只是math.round达到第一个高度,它的工作原理与假设的相同。

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

3

您可以尝试以下代码,

$("#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

当检查可滚动元素(即不是window)时,这将提供准确的结果:

// `element` is a native JS HTMLElement
if ( element.scrollTop == (element.scrollHeight - element.offsetHeight) )
    // Element scrolled to bottom

offsetHeight应该给出元素的实际可见高度(包括填充,边距滚动条),并且scrollHeight整个元素高度,包括不可见(溢出)区域。

jQuery.outerHeight()结果应该与JS类似-MDN中的.offsetHeight文档offsetHeight尚不清楚其跨浏览器的支持。为了涵盖更多选项,此方法更加完整:

var offsetHeight = ( container.offsetHeight ? container.offsetHeight : $(container).outerHeight() );
if  ( container.scrollTop == (container.scrollHeight - offsetHeight) ) {
   // scrolled to bottom
}

尝试Math.floor(element.scrollTop) === element.scrollHeight - element.offsetHeight万一scrollTop的是它不会工作没有小数点Math.floor()
米凯尔MICHAILIDIS

1

所有这些解决方案在Firefox和Chrome上都不适合我,因此我使用Miles O'Keefemeder 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

这是我的两分钱,因为被接受的答案对我不起作用。

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

1

不是听滚动事件,使用的交会观测物美价廉一个检查,如果最后一个元素是在视窗(这意味着用户已滚动至底部)可见。它也支持带有polyfill的 IE7 。

var observer = new IntersectionObserver(function(entries){
   if(entries[0].isIntersecting === true)
      console.log("Scrolled to the bottom");
   else
      console.log("Not on the bottom");
}, {
   root:document.querySelector('#scrollContainer'),
   threshold:1 // Trigger only when whole element was visible
});

observer.observe(document.querySelector('#scrollContainer').lastElementChild);
#scrollContainer{
  height: 100px;
  overflow: hidden scroll;
}
<div id="scrollContainer">
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
  <div>Item 4</div>
  <div>Item 5</div>
  <div>Item 6</div>
  <div>Item 7</div>
  <div>Item 8</div>
  <div>Item 9</div>
  <div>Item 10</div>
</div>


Intersection Observer的问题在于,如果起始窗口相对较小(例如在获取没有滚动条的图像之前的基本布局),则立即触发观察者回调。滚动侦听器实际上是在等待一个人滚动。并且在获取第一批图像等之前不会出现滚动条。因此,Intersection Observer并不是一种解决方案。
阿列克斯

@Aleks您可以致电 .observe(...)像在用户悬停/触摸您的滚动容器时那样在事件侦听器上这样它就不会立即触发。
StefansArya

0

让我展示没有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";  }

5
这不能回答问题。问题是如何检测用户是否一直将窗口滚动到底部。您的代码正在检查是否有特定元素在显示。
彼得·霍尔

0

我使用了@ddanone 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();
    }
}

}


0

停止重复提醒尼克的回答

ScrollActivate();

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

0

如果您致电,Google Chrome会显示整个页面的高度 $(window).height()

而是使用window.innerHeight来获取窗口的高度。必要的检查应为:

if($(window).scrollTop() + window.innerHeight > $(document).height() - 50) {
    console.log("reached bottom!");
}

0

显然,对我有用的是“身体”而不是“窗口”,如下所示:

$('body').scroll(function() {


 if($('body').scrollTop() + $('body').height() == $(document).height()) {
     //alert at buttom
 }
 });

为了跨浏览器兼容性使用:

  function getheight(){
    var doc = document;
    return  Math.max(
        doc.body.scrollHeight, doc.documentElement.scrollHeight,
        doc.body.offsetHeight, doc.documentElement.offsetHeight,
        doc.body.clientHeight, doc.documentElement.clientHeight

        );
   }

然后代替$(document).height()调用函数getheight()

$('body').scroll(function() {


   if($('body').scrollTop() + $('body').height() == getheight()  ) {
     //alert at bottom
 }
});

适用于近底使用:

$('body').scroll(function() {


if($('body').scrollTop() + $('body').height() > getheight() -100 ) {
    //alert near bottom
 }
 });
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.