实现无限滚动
随着用户滚动自动加载更多内容
实现无限滚动 是 CoddyKit 上的免费 HTML Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 HTML Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 HTML Academy 课程共包含 4 节课。
实现模式
无限滚动会在用户接近列表底部时加载更多内容。最简洁的实现方式是使用 IntersectionObserver:在列表末尾放置一个 sentinel 元素并观察它。当 sentinel 进入视口时,获取下一个 page。
sentinel 元素
在最后一个列表项之后追加一个不可见的 <div>(或“加载中……”占位符)。使用 IntersectionObserver 观察它。当它发生交叉时,就表示用户已经滚动到接近底部的位置——此时应加载更多内容。
<ul id="feed">
<li>Post 1</li>
<li>Post 2</li>
</ul>
<div id="sentinel" aria-hidden="true"></div>观察器循环
发生交叉时:获取下一个 page,渲染新项目,并重新定位 sentinel(只要在 sentinel 之前追加项目,它就会自动保持在列表末尾)。无需取消观察再重新观察,sentinel 仍处于观察状态。
const sentinel = document.getElementById("sentinel");
const feed = document.getElementById("feed");
let page = 1;
let loading = false;
const observer = new IntersectionObserver(async (entries) => {
if (!entries[0].isIntersecting || loading) return;
loading = true;
const items = await fetchPage(page++);
items.forEach((it) => feed.insertAdjacentHTML("beforeend", renderItem(it)));
loading = false;
});
observer.observe(sentinel);加载状态保护
布尔值 loading 标志可以防止请求堆积:如果用户快速滚动,在第一个响应到达前触发了多次交叉,就不会重复发起请求。没有这个保护时,同一个 page 会被重复获取,项目也会重复出现。
数据结束
当服务器返回空 page(或表示“没有更多内容”)时,请取消观察 sentinel,并将其替换为列表结束消息。之后的交叉不会再触发获取请求,用户也能看到自己已经到达末尾。
错误处理
请将获取请求放在 try/catch 中。发生错误时,让 loading = true 保持不变,以免自动触发重试;显示一个“重试”按钮,由它重置 loading 并再次触发加载。否则,网络故障可能导致重试风暴。
使用 rootMargin 提前加载
rootMargin: "500px" 会在用户到达 sentinel 前 500 像素开始获取下一个 page。请根据项目高度和平均滚动速度进行调整:设置过小,用户会遇到“暂无内容”;设置过大,则会提前获取超出需求的内容。
恢复滚动位置
用户离开后返回时,应保留滚动位置 AND 重新渲染之前加载的项目。请将项目缓存到 sessionStorage 或类似 Zustand 的存储中;挂载时恢复项目,并使用 scrollTo 滚动到记住的偏移量。
内存注意事项
较长的无限滚动会累积数千个 DOM 节点。对于非常长的 feed(Twitter、Facebook),请结合窗口化:从 DOM 中移除视口上方的项目,并在用户向上滚动时恢复它们。react-virtual 或 @tanstack/virtual 等库可以高效地处理这一过程。
可访问性
对于难以触达页脚的键盘用户和屏幕阅读器用户,无限滚动并不友好。请提供一个备用的“加载更多”按钮,并确保页面有一个可以通过 Home/End 键访问的真正页脚。使用 Aria-live 区域播报新项目也会有所帮助。
移动端回弹滚动
iOS 的回弹滚动可能会在接近底部时多次触发交叉。加载保护可以处理大多数情况;您也可以加入 300ms 的去抖,以过滤回弹期间产生的交叉突发事件。
替代方案:基于游标的分页
服务器 API 应返回“下一个游标”,而不是依赖客户端跟踪的 page 编号,这样可以稳健地应对滚动期间项目的插入或删除。客户端在每次请求中传递游标,并在服务器不再返回游标时停止。
知识检查
为什么无限滚动的 IntersectionObserver 回调中必须有“加载”标志?
总结
无限滚动会在列表末尾的哨兵元素上使用 IntersectionObserver。发生相交时,获取下一页、渲染内容,并继续观察。使用加载标志进行保护,妥善处理数据结束和错误,并调整 rootMargin 以控制预取距离。提供键盘操作替代方案(“加载更多”按钮),并考虑对超长信息流进行窗口化处理。
常见问题解答
「实现无限滚动」课时是免费的吗?
是的 — 「实现无限滚动」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 HTML Academy 课程的其余内容,请升级到 CoddyKit PRO。 HTML Academy 课程共包含 4 节课。
「实现无限滚动」这节课中我会学到什么?
随着用户滚动自动加载更多内容 你通过在浏览器中直接运行的动手代码来练习 HTML Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 HTML Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 HTML Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「实现无限滚动」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 HTML Academy 课中编写并运行代码吗?
能。每节 HTML Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。