📖 小说网站预导航技术全解:秒开下一章 + 浏览器前进/后退支持
一、前言
在小说网站中,点击「下一章」通常需要等待网络请求,体验不佳。为提升用户阅读体验,很多网站采用 预导航(Prefetch / Pre-navigation) 技术:提前获取下一章内容,点击时立即展示。
本文将从三个角度详细介绍实现方式:
- HTML
<link>
预加载(最简单,零 JS 方案) - JS
fetch
主动预加载(可控性更高) -
fetch + History API
(支持浏览器前进/后退,最佳体验) - 如何通过
history.back()
控制浏览器箭头显示
二、方式一:<link rel="prefetch">
HTML5 提供了原生预取机制,写在 <head>
中:
<link rel="prefetch" href="/chapter2.html" as="document">
- prefetch:浏览器空闲时预加载资源(下一章 HTML / 图片等)
- prerender:在后台完整渲染页面,点击时几乎零延迟,但兼容性较差
优点:
- 实现简单,一行代码搞定
- 浏览器自动缓存资源
缺点:
- 无法控制加载时机
- 不会自动与浏览器前进/后退联动
适用场景: 简单优化,如博客或小说目录页
三、方式二:JS fetch
主动预加载
如果需要更精确的控制,可用 JS fetch
:
let nextUrl = "/chapter2.html";
let cache = null;
// 页面加载时预取下一章
fetch(nextUrl)
.then(res => res.text())
.then(html => cache = html);
// 点击下一章
document.getElementById("next").addEventListener("click", (e) => {
e.preventDefault();
if (cache) {
document.getElementById("content").innerHTML = cache;
} else {
location.href = nextUrl;
}
});
优点:
- 精确控制加载时机
- 可缓存多章内容
缺点:
- 浏览器前进/后退按钮失效(未写入历史栈)
四、方式三:fetch + History API
(推荐🔥)
为了让前进/后退按钮也能秒开,需要结合 pushState
和 popstate
:
const contentEl = document.getElementById("content");
let preloadCache = {};
// 初始化历史栈
history.replaceState({ html: contentEl.innerHTML }, "", location.href);
// 预取下一章
function preload(url) {
if (preloadCache[url]) return;
fetch(url)
.then(res => res.text())
.then(html => {
const doc = new DOMParser().parseFromString(html, "text/html");
preloadCache[url] = doc.querySelector("#content").innerHTML;
});
}
// 点击切换章节
document.querySelectorAll("a.nav").forEach(link => {
link.addEventListener("click", async (e) => {
e.preventDefault();
const url = link.href;
let newContent = preloadCache[url];
if (!newContent) {
const res = await fetch(url);
const html = await res.text();
const doc = new DOMParser().parseFromString(html, "text/html");
newContent = doc.querySelector("#content").innerHTML;
}
contentEl.innerHTML = newContent;
history.pushState({ html: newContent }, "", url);
// 顺便预取下一章
const next = link.nextElementSibling?.href;
if (next) preload(next);
});
});
// 浏览器前进/后退
window.addEventListener("popstate", (e) => {
if (e.state && e.state.html) {
contentEl.innerHTML = e.state.html;
} else {
location.reload();
}
});
优点:
- 点击下一章秒开
- 前进/后退按钮秒开
- 可扩展多章预取策略
缺点:
- 需要额外 JS 逻辑
- 刷新页面仍需服务端响应
五、控制浏览器箭头可用
- 浏览器前进按钮只有在 有可前进历史 时才激活
- pushState 不会自动激活前进按钮
- 可行方法:先创建多条历史,然后调用
history.back()
// 初始化
history.replaceState({id:1},"","#1");
history.pushState({id:2},"","#2");
// 此时前进按钮仍灰色
history.back(); // 后退到第1章,前进按钮可用
JS 无法直接让浏览器箭头激活,只能通过创建历史并后退实现
六、方案对比
方案 | 代码复杂度 | 可控性 | 前进/后退支持 | 适用场景 |
---|---|---|---|---|
<link rel="prefetch"> |
极低 | 低 | ❌ | 简单优化 |
JS fetch
|
中 | 高 | ❌ | 定制预取策略 |
fetch + History API |
高 | 高 | ✅ | 小说网站 / 阅读器 |
七、进一步优化思路
- 条件预取:根据
navigator.connection.saveData
判断是否省流量 - 多章节预取:提前缓存后两章,实现点击前进秒开
- Service Worker:离线缓存,断网也能阅读
- 无限滚动:直接拼接章节,去掉翻页操作
八、总结
-
最简单方式:
<link rel="prefetch">
,无需 JS -
更灵活方式:JS
fetch
,可缓存下一章 -
最佳体验方式:
fetch + History API
,前进/后退全支持
👉 对于小说网站,推荐第三种方案,配合预加载和缓存,可实现媲美本地阅读器的流畅体验