检查用户是否滚动到底部(不仅仅是窗口,而是任何元素)
我正在制作一个分页系统(有点像 Facebook),当用户滚动到底部时会加载内容。我认为最好的方法是找到用户何时位于页面底部并运行 Ajax 查询来加载更多帖子。
唯一的问题是我不知道如何检查用户是否已滚动到页面底部。有什么想法吗?
我正在使用 jQuery,因此请随意提供使用它的答案。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
在
window
.scroll()
事件>,像这样:你可以在这里测试,这需要窗口的顶部滚动,那么如何它向下滚动,添加可见窗口的高度并检查它是否等于整体内容(
文档
)的高度。如果您想检查用户是否接近底部,则看起来像这样:您可以在此处测试该版本,只需将
100
调整为您想要触发的底部的任何像素即可。Use the
.scroll()
event onwindow
, like this:You can test it here, this takes the top scroll of the window, so how much it's scrolled down, adds the height of the visible window and checks if that equals the height of the overall content (
document
). If you wanted to instead check if the user is near the bottom, it'd look something like this:You can test that version here, just adjust that
100
to whatever pixel from the bottom you want to trigger on.TL;博士;
概念
从本质上讲,“滚动到底部”是指可滚动区域 (
scrollHeight
) 减去可见内容距顶部的距离 (scrollTop
) 的时刻等于可见内容的高度 (clientHeight
)。换句话说,当这种等价性成立时,我们就会“滚动”::
防止舍入错误
提到 但是,其中一些属性是四舍五入的< /a>,这意味着在
scrollTop
具有小数部分或舍入值对齐不良的情况下,相等可能会失败。通过将绝对差值与可容忍的阈值进行比较,可以缓解该问题:
防止路由错误的代码片段可能如下所示:
请注意,我添加了一个对于其容器而言太大而无法强制滚动的 div,但无需将内容“包装”在另一个元素中,直接在元素中添加文本会使元素溢出。
去抖动、延迟和节流
我对它了解得越多,就越发现它不在这个答案的范围内(这个代码审查问题及其答案,以及这个链接的文章很有趣),但在特定情况下(如果处理程序执行昂贵的计算,如果我们将动画绑定到滚动事件,如果我们只想在滚动运动结束时启动事件,或者任何可能需要它的情况)它可以用于:
在选择执行这些操作时必须非常小心,例如限制事件可能会阻止最后一个滚动条触发,这可能会完全击败无限滚动条。
大多数时候,不做这三件事中的任何一件都可以很好地工作,因为只是看看我们是否完全滚动是相对便宜的。
TL;DR;
Concept
At its core, "having scrolled to the bottom" refers to the moment when the scrollable area (
scrollHeight
) minus the distance of the visible content from the top (scrollTop
) equals the height of the visible content (clientHeight
).Differently put, we are "scrolled" when this equivalence is true::
Preventing Rounding Error
As mentioned however, some of these properties are rounded, which means that the equality can fail in cases where
scrollTop
would have a decimal component or when the rounded values align poorly.It is possible to mitigate that problem by comparing the absolute difference to a tolerable threshold:
A snippet that prevents rouding error could look like this:
Note that I've added a div that is too big for its container to force the scrolling but there's no need to "wrap" the content in another element, text directly in an element would make the element overflow.
Debouncing, Delaying and Throttling
The more I understand about it and the less I find it's within the scope of this answer (this Code Review question and its answer, and this linked article are of interest), but in specific cases (if the handler does expensive computation, if we tie an animation to the scroll event, if we only want to launch the event at the end of the scroll motion, or any situation that may warrants it) it can be useful to:
Great care must be taken in choosing to do any of these things, for instance throttling the event could prevent the last scroll to fire, which could completely defeat an infinite scroller.
Not doing any of those three things works perfectly fine most of the time, as just looking if we're completely scrolled is relatively inexpensive.
Nick Craver 的答案 工作正常,避免了
$(document).height()
的值因浏览器而异的问题。要使其适用于所有浏览器,请使用 James Padolsey< /a>:
代替
$(document).height()
,因此最终代码为:Nick Craver's answer works fine, spare the issue that the value of
$(document).height()
varies by browser.To make it work on all browsers, use this function from James Padolsey:
in place of
$(document).height()
, so that the final code is:进一步的优秀接受 Nick Craver 的回答,您可以限制滚动事件,使其不会频繁触发,从而提高浏览器性能:
Further to the excellent accepted answer from Nick Craver, you can throttle the scroll event so that it is not fired so frequently thus increasing browser performance:
Nick Craver 的答案 需要稍微修改一下才能在 iOS 6 Safari Mobile 上工作,并且应该是:
更改 $( window).height() 到 window.innerHeight 应该这样做,因为当地址栏隐藏时,会添加额外的 60 像素窗口的高度,但使用
$(window).height()
不会反映此更改,而使用window.innerHeight
则会反映此更改。注意:
window.innerHeight
属性还包括水平滚动条的高度(如果已呈现),与$(window).height()
不同其中不包括水平滚动条的高度。这在 Mobile Safari 中不是问题,但可能会导致其他浏览器或未来版本的 Mobile Safari 中出现意外行为。将==
更改为>=
可以解决大多数常见用例的问题。详细了解
window.innerHeight
属性 这里。Nick Craver's answer needs to be slightly modified to work on iOS 6 Safari Mobile and should be:
Changing $(window).height() to window.innerHeight should be done because when the address bar is hidden an additional 60 pixels are added to the window's height, but using
$(window).height()
does not reflect this change, while usingwindow.innerHeight
does.Note: The
window.innerHeight
property also includes the horizontal scrollbar's height (if it is rendered), unlike$(window).height()
which will not include the horizontal scrollbar's height. This is not a problem in Mobile Safari, but could cause unexpected behavior in other browsers or future versions of Mobile Safari. Changing==
to>=
could fix this for most common use cases.Read more about the
window.innerHeight
property here.这是一个相当简单的方法
const didScrollToBottom = elm.scrollTop + elm.clientHeight == elm.scrollHeight
示例
其中
elm
是从 ie 检索的元素document.getElementById
。Here's a fairly simple approach
const didScrollToBottom = elm.scrollTop + elm.clientHeight == elm.scrollHeight
Example
Where
elm
is an element retrieved from i.edocument.getElementById
.请检查此答案 。
您可以执行
footerHeight - document.body.offsetHeight
来查看您是否靠近页脚或到达页脚。Please check this answer.
You can do
footerHeight - document.body.offsetHeight
to see if you are near the footer or reached the footer.这是一段可以帮助您调试代码的代码。我测试了上面的答案,发现它们有问题。我已在 Chrome、Internet Explorer、Firefox、iPad (Safari)。我没有安装任何其他解决方案来测试...
可能有一个更简单的解决方案,但我停在了它起作用的地方
如果您仍然遇到问题对于一些流氓浏览器,这里有一些代码可以帮助您调试:
Here is a piece of code that will help you debug your code. I tested the above answers and found them to be buggy. I have tested the following on Chrome, Internet Explorer, Firefox, iPad (Safari). I don't have any others installed to test...
There may be a simpler solution, but I stopped at the point at which it worked
If you are still having problems with some rogue browser, here is some code to help you debug:
它计算滚动条到元素底部的距离。
如果滚动条到达底部,则等于 0。
It calculates distance scroll bar to bottom of element.
Equal 0, if scroll bar has reached bottom.
这是一个普通的 JavaScript 解决方案,使用 ES6 和
debounce
:演示: https:// jsbin.com/jicikaruta/1/edit?js,output
参考文献:
Here is a vanilla JavaScript solution that uses ES6 and
debounce
:Demo: https://jsbin.com/jicikaruta/1/edit?js,output
References:
这是我的两分:
This is my two cents:
使用 Intersection Observer 是最便宜的检查工具如果最后一个元素在视口上可见(这意味着用户已滚动到底部)。它还通过 polyfill。
Instead of listening to the scroll event, using Intersection Observer is the inexpensive one for checking if the last element was visible on the viewport (that means the user has scrolled to the bottom). It also supported for Internet Explorer 7 with the polyfill.
我的纯js解决方案:
My solution in plain js:
尼克回答说很好,但是您将拥有在滚动时重复自身的功能,或者如果用户缩放了窗口则根本无法工作。我想出了一个简单的解决办法,只需 math.round 第一个高度,它的工作原理就像假设的那样。
Nick answers its fine but you will have functions which repeats itsself while scrolling or will not work at all if user has the window zoomed. I came up with an easy fix just math.round the first height and it works just as assumed.
我用纯 JavaScript 以一种非常简单的方式完成了这一点:
I have done this in a very easy way with pure JavaScript:
如果有人想要一个普通的 JavaScript 解决方案,并且需要检测用户何时滚动到
的底部,我设法使用这些代码行来实现它
In case someone wants a vanilla JavaScript solution and needs to detect when a user has scrolled to the bottom of a
<div>
I managed to implement it by using these lines of code我使用此测试来检测滚动到达底部:
event.target.scrollTop === event.target.scrollHeight - event.target.offsetHeight
I used this test to detect the scroll reached the bottom:
event.target.scrollTop === event.target.scrollHeight - event.target.offsetHeight
Safari 可以滚动到页面底部,这导致我们的应用程序出现错误。使用
>=
而不是===
解决此问题。Safari can scroll past the bottom of the page which was causing a bug in our application. Solve this using
>=
instead of===
.所有这些解决方案在 Firefox 和 Chrome 上都不适合我,因此我使用 Miles O'Keefe 和 < a href="https://stackoverflow.com/a/3333336/3406616">meder omuraliev 像这样:
All these solutions doesn't work for me on Firefox and Chrome, so I use custom functions from Miles O'Keefe and meder omuraliev like this:
您可以尝试以下代码,
You can try the following code,
如果滚动到底部,请尝试此匹配条件
Try this for match condition if scroll to bottom end
当检查可滚动元素(即不是
窗口
)时,这会给出准确的结果:offsetHeight
应该给出实际可见 元素的高度(包括内边距、边距、和滚动条),scrollHeight
是元素的整个高度,包括不可见(溢出)地区。jQuery
的.outerHeight()
应该给出与 JS 的.offsetHeight
类似的结果 --MDN 中关于 offsetHeight 的文档并不清楚其跨浏览器支持。为了涵盖更多选项,这更加完整:
This gives accurate results, when checking on a scrollable element (i.e. not
window
):offsetHeight
should give the actual visible height of an element (including padding, margin, and scrollbars), andscrollHeight
is the entire height of an element including invisible (overflowed) areas.jQuery
's.outerHeight()
should give similar result to JS's.offsetHeight
--the documentation in MDN for
offsetHeight
is unclear about its cross-browser support. To cover more options, this is more complete:这是我的两分钱,因为接受的答案对我不起作用。
Here's my two cents as the accepted answer didn't work for me.
(2021)
这里的很多答案都涉及对
element
的引用,但如果您只关心整个页面,只需使用:(2021)
Lots of answers here involve a ref to an
element
, but if you only care about the whole page, just use:我使用了 ddanone 的回答并添加了 Ajax 调用。
I used ddanone's answer and added an Ajax call.
如果您调用
$(window).height()
,Google Chrome 就会给出页面的完整高度。相反,使用 window.innerHeight 来检索窗口的高度。
必要的检查应该是:
Google Chrome gives the full height of the page if you call
$(window).height()
.Instead, use
window.innerHeight
to retrieve the height of your window.The necessary check should be:
许多其他解决方案对我不起作用,因为滚动到底部时,我的 div 触发了警报两次,向上移动时也触发了几个像素,因此解决方案是:
Many other solutions don't work for me, because on scroll to the bottom, my div was triggering the alert two times and when moving up it was also triggering up to a few pixels so the solution is:
尝试了所有答案,但没有一个对我有用。但是,一些答案没有考虑缩放问题,当用户放大或缩小时,计算可能无法按预期进行。
以下是您需要在 ReactJS 中执行的操作:
假设我们有一个物理屏幕分辨率为 1920x1080 像素且设备像素比为 2 的设备。这意味着设备的虚拟屏幕分辨率为 960x540 CSS 像素(由于设备像素比为 2,因此 CSS 像素数是物理像素数的一半)。
现在假设我们要计算视口的物理像素高度。我们可以通过将 CSS 像素中的视口高度(可以使用 document.documentElement.clientHeight 获得)乘以设备像素比(可以使用 window.devicePixelRatio 获得)来实现此目的)。
因此,如果以 CSS 像素为单位的视口高度为 540,则:
在本示例中,viewportHeightInPixels 将等于 1080,因为我们已将以 CSS 像素为单位的视口高度(即 540)乘以设备像素比 (<是 2)。
这告诉我们,视口的物理像素高度为1080,这与设备的物理屏幕分辨率相同。
下面是一个示例代码片段,它使用此计算来检查用户是否已滚动到页面底部:
以下是如何在 JSX 代码中使用它:
Trying all the answers, none of them worked for me. However, some of the answers did not take into account the issue of zooming, where the calculation may not work as expected when the user zooms in or out.
Here is what you need to do in ReactJS :
Let's say we have a device with a physical screen resolution of 1920x1080 pixels and a device pixel ratio of 2. This means that the device has a virtual screen resolution of 960x540 CSS pixels (since the device pixel ratio is 2, the number of CSS pixels is half the number of physical pixels).
Now let's say we want to calculate the height of the viewport in physical pixels. We can do this by multiplying the height of the viewport in CSS pixels (which we can get using
document.documentElement.clientHeight
) by the device pixel ratio (which we can get usingwindow.devicePixelRatio
).So, if the height of the viewport in CSS pixels is 540, then:
In this example, viewportHeightInPixels would be equal to 1080, since we've multiplied the viewport height in CSS pixels (which is 540) by the device pixel ratio (which is 2).
This tells us that the height of the viewport in physical pixels is 1080, which is the same as the device's physical screen resolution.
Here is an example code snippet that uses this calculation to check if the user has scrolled to the bottom of the page:
Here is how you can use it in your JSX code:
停止重复提醒尼克的回答
To stop repeated alert of Nick's answer
这是最简单的方法:
Here is the most simple way to do it: