我正在制作一个分页系统(有点像Facebook),当用户滚动到底部时,内容就会加载。我认为最好的方法是找到用户在页面底部的时间,然后运行Ajax查询来加载更多的帖子。

唯一的问题是我不知道如何检查用户是否已经滚动到页面的底部。什么好主意吗?

我使用jQuery,所以请随意提供使用它的答案。


当前回答

Safari可以滚动到导致应用程序错误的页面底部。用>=代替===来解决这个问题。

container.scrollTop >= container.scrollHeight - container.clientHeight

其他回答

显然,对我有用的是“身体”,而不是像这样的“窗口”:

$('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

        );
   }

然后调用函数getheight()而不是$(document).height()

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

Nick Craver的回答需要稍作修改,以适应iOS 6 Safari Mobile,应该是:

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

将$(window).height()更改为window。innerHeight应该这样做,因为当地址栏被隐藏时,一个额外的60px被添加到窗口的高度,但使用$(window).height()不会反映这个变化,而使用window。innerHeight。

注:窗口。innerHeight属性还包括水平滚动条的高度(如果它被渲染),不像$(window).height()不包括水平滚动条的高度。这在Mobile Safari中不是问题,但在其他浏览器或未来版本的Mobile Safari中可能会导致意想不到的行为。将==更改为>=可以修复大多数常见用例的这个问题。

阅读更多关于窗户的内容。这里的innerHeight属性

这给出了准确的结果,当检查一个可滚动的元素(即不是窗口):

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

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

jQuery的.outerHeight()应该给出与JS的.offsetHeight——类似的结果 offsetHeight的MDN文档不清楚它的跨浏览器支持。为了涵盖更多选项,这是更完整的:

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

而不是监听滚动事件,使用交集观察者是检查最后一个元素是否在视口可见的最便宜的一个(这意味着用户被滚动到底部)。它也支持IE7的polyfill。

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>

TL; diana;

Math.abs(element.scrollHeight - element.scrollTop - element.clientHeight) < 1

概念

在其核心,“已经滚动到底部”指的是可滚动区域(scrollHeight)减去可见内容到顶部(scrollTop)的距离等于可见内容的高度(clientHeight)的时刻。

换句话说,当这个等价为真时,我们被“滚动”::

scrollHeight - scrollTop - clientHeight === 0

防止舍入错误

但是,如上所述,其中一些属性是四舍五入的,这意味着在scrollTop有小数组件或四舍五入值对齐不好的情况下,相等性可能会失败。

通过将绝对差异与可容忍的阈值进行比较,可以缓解这个问题:

Math.abs(element.scrollHeight - element.clientHeight - element.scrollTop) < 1

防止舍入错误的代码片段如下所示:

. getelementbyid(“constrained-container”)。addEventListener('scroll', event => { const {scrollHeight, scrollTop, clientHeight} = event.target; 如果(数学。abs(scrollHeight - clientHeight - scrollTop) < 1) { console.log(滚动); } }); # constrained-container { 身高:150 px; overflow-y:滚动; } # very-long-content { 身高:600 px; } < div id = " constrained-container " > < div id = " very-long-content " > 把我滚动到底部 < / div > < / div >

注意,我添加了一个div,对于它的容器来说,它太大了,无法强制滚动,但没有必要将内容“包装”到另一个元素中,直接在元素中输入文本会使元素溢出。

跳脱,延迟和节流

我对它了解得越多,我发现它在这个答案的范围内就越少(这个codereview问题及其答案,以及这篇链接的文章都很有趣),但在特定情况下(如果处理程序执行昂贵的计算,如果我们将动画绑定到滚动事件,如果我们只想在滚动运动结束时启动事件,或者任何可能保证它的情况),它可以用于:

Debounce(当第一次滚动发生时触发处理程序,然后防止它太快触发), 延迟(阻止处理程序的执行,直到滚动事件在一段时间内没有触发。这在Ecmascript上下文中通常被称为deboning), 或者节流(防止训练者在一段时间内射击一次以上)。

在选择做这些事情时必须非常小心,例如,限制事件可以防止最后一个卷轴发射,这可能会完全击败无限卷轴。

大多数时候,不做这三件事中的任何一件都是完美的,因为仅仅看看我们是否完全滚动是相对便宜的。