📢 新文章推送 · 每周更新优质内容 · 订阅更新 →
向下滚动
测试笔记

浏览位置记忆功能实现

AI 智能总结

需求场景

读者浏览博客时常遇到这种情况:在首页滚动到第 3 屏找到一篇文章,点进去阅读,看完返回首页时,页面回到了顶部,又需要手动滚动到之前的位置。这种体验很割裂,尤其对于内容列表较长的页面。

使用 sessionStorage 记录每个页面的滚动位置,在用户返回时自动恢复,可以实现类似单页应用的无缝浏览体验。

核心实现

创建 scroll-memory.js 模块:

 1class ScrollMemory {
 2  constructor() {
 3    this.throttleDelay = 300;
 4    this.lastSaveTime = 0;
 5    this.init();
 6  }
 7
 8  init() {
 9    this.restore();
10    window.addEventListener('scroll', this.handleScroll.bind(this), {
11      passive: true
12    });
13  }
14
15  handleScroll() {
16    const now = Date.now();
17    if (now - this.lastSaveTime < this.throttleDelay) return;
18    this.lastSaveTime = now;
19    this.save();
20  }
21
22  save() {
23    const key = `scroll:${location.pathname}`;
24    sessionStorage.setItem(key, window.scrollY.toString());
25  }
26
27  restore() {
28    const key = `scroll:${location.pathname}`;
29    const saved = sessionStorage.getItem(key);
30    if (saved !== null) {
31      const targetY = parseInt(saved, 10);
32      window.scrollTo({ top: targetY, behavior: 'instant' });
33    }
34  }
35}
36
37export default ScrollMemory;

关键技术点

被动事件监听

添加滚动监听时传入 { passive: true } 选项。这告诉浏览器该监听器不会调用 preventDefault(),浏览器无需等待 JS 执行完毕即可立即开始滚动,避免滚动卡顿。

节流优化(300ms)

handleScroll 中通过时间戳判断距上次保存是否超过 300ms。滚动事件可能以每秒 60 次以上的频率触发,不加节流将导致 sessionStorage.setItem() 被高频调用,引起不必要的性能开销。

按 pathname 索引

使用 scroll:${location.pathname} 作为存储键,确保不同页面(首页、分类页、归档页等)的滚动位置互不干扰。同一页面内不同 URL 参数(如分页)也通过完整的 pathname 自动区分。

使用 sessionStorage 而非 localStorage

sessionStorage 的数据在用户关闭标签页时自动清除,符合「本次浏览会话内保持位置」的需求。如果用 localStorage,位置会持久保留,可能造成用户下次打开站点时被滚动到不明所以的位置。

SWUP 兼容

SWUP 执行页面切换时 DOM 会被替换,需要在内容替换后重新执行恢复逻辑:

1import ScrollMemory from './scroll-memory.js';
2
3document.addEventListener('swup:contentReplaced', () => {
4  new ScrollMemory();
5});

SWUP 的页面切换不会触发完整的页面生命周期,因此需要手动重新初始化滚动记忆模块。但保存在 sessionStorage 中的数据不会因 SWUP 切换而丢失,这意味着:

  1. 从列表页点击文章 → sessionStorage 保存列表页位置
  2. 文章页渲染完毕,初始化 ScrollMemory(恢复的是文章页位置,可能为 0)
  3. 用户按返回或点击导航回列表页 → SWUP 替换内容 → 重新初始化 ScrollMemory → 恢复之前保存的滚动位置

边界处理

  • sessionStorage 不可用时(如隐私模式限制),getItem 返回 null,代码不做任何处理,自然降级
  • scrollTo 使用 behavior: 'instant' 而非 'smooth',避免恢复位置时产生可见的滚动动画
  • 若页面内容动态加载(如图片懒加载),恢复滚动位置时页面高度可能尚未稳定,可监听页面完全加载后再执行恢复
版权声明

本文作者 Lumin

本文链接 https://www.zhengquan.xyz/biji/scroll-position-memory/

许可协议 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!

请作者喝杯咖啡 ☕

  • 微信打赏
    微信支付
  • 支付宝打赏
    支付宝
点击按钮查看打赏二维码
🎁 推荐工具
试试这些实用在线工具,提升工作效率
前往工具集 →

留言评论

期待你的想法

评论加载中