754 字
4 分钟
Swup 与持久化外壳:无刷新导航的代价

第一次体验 Swup 时,最直观的感受是「顺」。点击链接,页面内容淡入替换,导航栏和侧栏原地不动,没有整页白屏。

但真正开始维护时,我发现无刷新导航并不是免费的。它改变的不只是体验,还有代码的生命周期。

外壳与内容的分工#

flowchart TB
  Shell[持久化外壳:导航、侧栏、页脚]
  Container[#swup-container:可替换页面内容]
  Shell --> Container
  Container --> PageA[页面 A]
  Container --> PageB[页面 B]

外壳只渲染一次,页面内容在每次导航时被替换。这样避免了重复渲染,但也带来一个关键问题:外壳里的代码不会因为路由变化而重新执行。

生命周期比事件名更重要#

如果一段逻辑依赖当前页面的数据,它就不能只在首次加载时运行。常见做法是监听 Swup 的生命周期:

在页面替换后重新初始化
document.addEventListener("astro:page-load", () => {
initPageScopedFeatures();
});

我在处理筛选器、代码块增强和图表初始化时,都同时验证了这两种路径。测试时不能只刷新页面,还要从其他页面点进来。

事件委托比重新绑定更稳#

页面内容被替换后,之前绑定在旧 DOM 上的事件监听器也会一起消失。与其每次导航后重新绑定,不如把监听器放在持久化的父节点上,用事件委托处理:

事件委托的例子
document.addEventListener("click", (event) => {
const target = event.target as HTMLElement;
const button = target.closest("[data-copy]");
if (!button) return;
copyToClipboard(button.dataset.copy ?? "");
});

体验与复杂度的交换#

方面普通整页导航Swup 无刷新导航
首屏切换有白屏过渡自然
状态保持全部重置外壳状态保留
代码复杂度低需要生命周期管理
调试难度低需要同时验证两条路径

无刷新导航买到的是体验,付出的是对生命周期的理解。

小结#

Swup 不是「装上就变好」的插件。它要求开发者明确区分「一次性外壳」和「可替换页面」,并在正确的生命周期里做正确的事。

理解这一点之后,无刷新导航才真正成为体验优化,而不是隐藏的 bug 来源。

第 7 篇,共 12 篇本文属于系列

Swup 与持久化外壳:无刷新导航的代价
https://www.ycera.cn/posts/swup-navigation/
作者
初月_Yuechu
发布于
2026-10-26
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取