唯一的问题是我不知道如何检查用户是否已滚动到页面底部。有什么建议吗?
我正在使用jQuery,所以请提供使用它的答案。
使用window
上的.scroll()
事件,如下所示:
$(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
调整为您想要触发的距离底部的像素即可。
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
document.getElementById('constrained-container').addEventListener('scroll', event => {
const {scrollHeight, scrollTop, clientHeight} = event.target;
if (Math.abs(scrollHeight - clientHeight - scrollTop) < 1) {
console.log('scrolled');
}
});
#constrained-container {
height: 150px;
overflow-y: scroll;
}
#very-long-content {
height: 600px;
}
<div id="constrained-container">
<div id="very-long-content">
scroll me to the bottom
</div>
</div>
请注意,我添加了一个比其容器大得多的div来强制滚动,但没有必要在另一个元素中“包裹”内容,直接在元素中放置文本会导致元素溢出。
我对此有越来越多的理解,并且发现它超出了这个答案的范围(这个Code Review问题及其答案以及这篇相关文章很有意思),但在特定情况下(如果处理程序进行了昂贵的计算,如果我们将动画与滚动事件绑定,如果我们只想在滚动结束时触发事件,或者任何可能需要的情况),可以很有用:
在选择执行这些操作时必须非常小心,例如限制事件可能会防止最后一次滚动触发,从而完全破坏无限滚动。
大多数情况下,不执行这三个操作也可以正常工作,因为只需检查是否已完全滚动相对较便宜。
Math.abs(element.scrollHeight - element.scrollTop - element.clientHeight) <= 3.0
(将 3.0 替换为您认为适合您情况的像素公差)。这么做是因为(A) clientHeight
、scrollTop
和clientHeight
都是四舍五入的,如果它们全部对齐,可能会导致 3 像素的误差,(B) 用户很难看到 3 像素的差异,所以当用户 "认为" 他们已经滑动到页面底部时实际上并没有到达底部时,用户可能会认为您的网站有问题,(C) 某些设备(特别是无鼠标的设备)在滚动时可能会有奇怪的行为。 - Jack GNick 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).height()
,最终代码如下:
$(window).scroll(function() {
if($(window).scrollTop() + $(window).height() == getDocHeight()) {
alert("bottom!");
}
});
除了来自Nick Craver的优秀回答answer from 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);
}
尼克·克雷弗的回答需要稍作修改才能在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()
不会包括水平滚动条的高度。这在移动Safari中不是问题,但可能会导致其他浏览器或未来版本的移动Safari出现意外行为。将==
更改为>=
可以解决大多数常见用例的问题。
了解有关window.innerHeight
属性的更多信息在此处。
这里有一个相当简单的方法
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
是从document.getElementById
获取的元素。
window.onscroll = function(ev) {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
console.log("bottom");
}
};
您可以执行 footerHeight - document.body.offsetHeight
来判断是否接近页脚或已到达页脚。
这里有一段代码可以帮助您调试程序。我测试了上面的答案,发现它们有漏洞。我在 Chrome、Internet Explorer、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;">
var elemScrolPosition = elem.scrollHeight - elem.scrollTop - elem.clientHeight;
它计算元素底部到滚动条的距离。如果滚动条已经滑动到底部,则为0。
scrollTop
不是四舍五入的(可能是小数),所以有时候即使滚动到底部,值也不是0。 - trusktr这是我的两分意见:
$('#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');
}
});