809 字
4 分钟
Fuwari 博客改造计划:为页面添加“双向滚动”控制(置顶与置底)

为什么需要双向滚动?#

Fuwari 原生只提供了一个“返回顶部”按钮。但在实际阅读长文或翻阅评论区时,用户往往也需要快速“直达底部”。为了保持界面的一致性,我们将这两个功能整合在同一个视觉区域,通过智能的算法自动判断该显示哪一个按钮,从而提升导航效率。


设计架构#

这是一个典型的“状态驱动”交互,我们需要处理好 UI、逻辑与框架生命周期的协作:

1. UI 表现层 (Component Layer)#

我们将原有的单按钮组件重构为 flex-col 垂直排列的按钮组。

  • 容器定位:使用 fixed 定位在屏幕右侧,并利用 transform 处理初始的隐藏偏移。
  • 视觉反馈:通过 transition 实现平滑的缩放和位移过渡。

2. 核心逻辑层 (Logic Layer)#

  • 滚动判定:通过 window.onscroll 实时对比 scrollTop(当前滚动距离)、clientHeight(视口高度)与 scrollHeight(页面总高度)。
  • 智能互斥
    • 当页面不在顶部时,显示“返回顶部”。
    • 当页面距离底部超过一定阈值(如 100px)时,显示“下滑到底部”。

3. 生命周期适配层 (Integration Layer)#

由于 Fuwari 使用了 Swup 路由,页面跳转时 DOM 会被替换。如果只在初次加载时获取按钮引用,跳转后脚本将无法找到新页面的按钮。

  • 重新初始化:必须在 Swup 的 page:view 钩子中重新执行 getElementById,确保逻辑始终绑定在当前的活动元素上。

核心实现步骤#

1. 重构基础组件#

修改 src/components/control/BackToTop.astro。我们将原来的 ID 移到了内部的按钮容器上,并引入了 Flex 布局。

<div class="scroll-controls-wrapper hidden lg:block">
<div class="scroll-controls-container flex flex-col gap-2">
<!-- 返回顶部 -->
<div id="back-to-top-btn" class="scroll-btn hide" onclick="window.scroll({top: 0, behavior: 'smooth'})">
<button class="btn-card h-[3.75rem] w-[3.75rem]">
<Icon name="material-symbols:keyboard-arrow-up-rounded" />
</button>
</div>
<!-- 下滑到底部 -->
<div id="scroll-to-bottom-btn" class="scroll-btn" onclick="window.scroll({top: document.documentElement.scrollHeight, behavior: 'smooth'})">
<button class="btn-card h-[3.75rem] w-[3.75rem]">
<Icon name="material-symbols:keyboard-arrow-down-rounded" />
</button>
</div>
</div>
</div>

2. 注入全局滚动算法#

src/layouts/Layout.astro 中找到 scrollFunction 并升级它。

关键代码解析:

function scrollFunction() {
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
let scrollHeight = document.documentElement.scrollHeight;
let clientHeight = document.documentElement.clientHeight;
// 如果向下滚动超过 Banner,显示返回顶部
if (scrollTop > bannerHeight) backToTopBtn.classList.remove('hide');
else backToTopBtn.classList.add('hide');
// 如果还没滚到底部(预留100px),显示滑到底部
if (scrollTop + clientHeight < scrollHeight - 100) {
scrollToBottomBtn.classList.remove('hide');
} else {
scrollToBottomBtn.classList.add('hide');
}
}

3. 解决 Swup 跳转失效问题#

这是很多改造者容易忽略的一步。在 Layout.astrosetup 函数中,我们需要监听 page:view 事件来重新获取 DOM 引用:

window.swup.hooks.on('page:view', () => {
// 页面跳转后,旧的按钮对象已不存在于文档中,必须重新获取
backToTopBtn = document.getElementById('back-to-top-btn');
scrollToBottomBtn = document.getElementById('scroll-to-bottom-btn');
});

细节优化建议#

  • 间距调整:我们在按钮组中使用了 gap-2,确保两个按钮之间有微小的缝隙,防止误触。
  • 阴影与背景:复用了 Fuwari 的 btn-card 类,使其在暗色模式下也能保持完美的视觉一致性。

结语#

通过这次改造,您的博客不仅能“快速回头”,也能“一冲到底”。这种对细节的极致追求,能显著降低用户在长文中的操作疲劳感。

Fuwari 博客改造计划:为页面添加“双向滚动”控制(置顶与置底)
https://fuwari.vercel.app/posts/fuwari博客改造计划为博客添加双向滚动控制/
作者
Watch Your Back
发布于
2026-04-05
许可协议
CC BY-NC-SA 4.0