自动翻页 —— 在任何页面上实现无限滚动
一个论坛、一个博客存档、搜索结果 —— 内容分散在 40 页里,底部有一个「下一页」链接。点击、等待、点击、等待。自动翻页替你做这件事:当你到达底部时,规则获取下一页并把它的内容接上去。给一个本没有无限滚动的页面加上无限滚动。
思路
每个分页页面有两样东西:一个「下一个」链接(通常是 <a rel="next">)和一个装真正内容的容器。自动翻页:
- 检测到你滚动到了接近底部。
- 通过
fetch获取下一页的 HTML。 - 提取内容容器,把它的子元素接到当前的后面。
- 用新页面的「下一个」链接替换原来的 —— 然后重复。
规则
规则的 JavaScript —— 把顶部的两个选择器改到具体网站:
const NEXT = 'a[rel="next"]';
const LIST = '#content';
let loading = false;
addEventListener('scroll', async () => {
if (loading || !document.querySelector(NEXT)) return;
if (innerHeight + scrollY < document.body.offsetHeight - 1200) return;
loading = true;
const next = document.querySelector(NEXT);
const html = await fetch(next.href).then(r => r.text());
const doc = new DOMParser().parseFromString(html, 'text/html');
const more = doc.querySelector(LIST);
if (more) document.querySelector(LIST).append(...more.childNodes);
const nn = doc.querySelector(NEXT);
nn ? (next.href = nn.href) : next.remove();
loading = false;
});
两个要调整的选择器
- NEXT —— 指向下一页的链接。
a[rel="next"]出人意料地经常有效;如果没有,用按钮的类名,例如.pagination-next。 - LIST —— 你要往后接的内容容器。在论坛里是帖子列表,在结果里是结果列表。在 JustZix 的 JS Console 里查一下它们共同的父元素是什么。
它如何工作
检测底部
innerHeight + scrollY 是窗口下边缘在文档里的位置。当它接近 document.body.offsetHeight(带 1200px 余量)时,就该再拉下来一些了。
loading 锁
scroll 事件每秒触发几十次。loading 标志确保一次只执行一个 fetch —— 没有它,你会把同一页接上去二十次。
DOMParser
fetch 把原始 HTML 作为文本返回。DOMParser 把它变成一个可查询的文档,querySelector 从中只提取内容容器 —— 不带新页面的页头、页脚和菜单。
坑
- 由 JavaScript 渲染的内容。如果页面只在 JS 里渲染列表,
fetch得到的原始 HTML 会是空的。自动翻页对服务端渲染的页面有效。 - 脚本不会执行。接上去的 HTML 是静态 DOM —— 新页面里的
<script>不会触发。对内容(文本、链接、图片)来说这不是问题。 - 文档会变大。接了 30 页之后 DOM 很重。这是无限滚动的代价 —— 时不时刷新一下页面。
另见
- 示例 —— 可直接粘贴的自动翻页代码片段
- 注入与 CSP —— 当 fetch 遇到限制时
- Output Console —— 观察规则在做什么
安装 JustZix —— 滚动,而不是点击「下一页」。
为这篇文章评分
暂无评分 — 成为第一个。