一招帮你记住上次读到哪儿了?

大家有没有注意到一个小问题,就是比如用手机看一篇技术文章或者小说的时候读到精彩处,不小心手滑刷新了页面,可是刚刚读到哪里了,是不是又得从头开始滑动屏幕去找,我到底读到哪里了, 这个有时候就很烦人。

那么我们作为牛马程序员能不能用技术解决这个问题呢?那肯定是可以的。

今天我们就来实现一下试试吧!

前端实现方式:

别被"自动记录位置"吓到,其核心逻辑清晰明了,主要依靠浏览器提供的几个强大工具:

  1. scroll 事件监听器:用户滚到哪里都知道 这是我们的"眼睛"。我们需要知道用户什么时候在滚动页面,以及滚动到了哪里。

    javascript 复制代码
    // 给window对象添加滚动事件监听
    window.addEventListener('scroll', function() {
      // 当用户滚动页面时,这个函数会被反复调用
      // 我们在这里记录当前滚动的位置
    });

    关键点: 但是这样子的话scroll 事件触发非常频繁,很难顶的。

  2. setTimeout + 防抖 (Debounce):给频繁滚动"踩刹车" 想象一下,用户快速滚动屏幕,scroll 事件不停地再触发。我们不需要记录每一个微小变动,只需要在用户滚动停下来一小会儿后,记录最终位置。这就是"防抖"。

    javascript 复制代码
    // 定义一个变量存放计时器
    let scrollTimer = null;
    
    window.addEventListener('scroll', function() {
      // 每次滚动,先清除之前的计时器(重置"冷静期")
      clearTimeout(scrollTimer);
    
      // 设置一个新的计时器,比如等待 250 毫秒(0.25秒)
      scrollTimer = setTimeout(function() {
        // 250毫秒内用户没有再滚动?好,认定他停下来了,现在记录位置!
        saveScrollPosition();
      }, 250);
    });
  3. sessionStorage:浏览器的临时记忆 用户滚动位置需要存起来。sessionStorage 还是比较好的了:

    • 会话级存储: 数据只在当前浏览器标签页的生命周期内有效。用户关闭标签页,数据就清空。
    • 键值对存储: 简单易用,像操作 JavaScript 对象。
    javascript 复制代码
    function saveScrollPosition() {
      // 1. 获取当前垂直滚动距离(最关键的数值!)
      const currentPosition = window.pageYOffset || document.documentElement.scrollTop;
    
      // 2. 把这个位置数字存入 sessionStorage,给它起个名字,比如 'lastScrollPos'
      sessionStorage.setItem('lastScrollPos', currentPosition.toString());
      // 注意:sessionStorage 只能存字符串,数字需要转成字符串
    }

    window.pageYOffset vs document.documentElement.scrollTop: 都是为了获取垂直滚动距离。pageYOffset 是更现代的标准方式,兼容性极好。加个 || 是为了老浏览器的备选方案,双保险。

用户回来时,自动归位

记录下位置只是成功了一半。当用户重新访问这个页面时(刷新、或从其他页面通过浏览器历史返回),我们需要读取存储的位置并自动滚动过去。

javascript 复制代码
// 当页面所有内容(包括图片等资源)都加载完毕时执行
window.addEventListener('load', function() {
  // 1. 尝试从 sessionStorage 读取我们之前存的 'lastScrollPos'
  const savedPosition = sessionStorage.getItem('lastScrollPos');

  // 2. 检查是否真的有存过这个值(第一次访问就没有)
  if (savedPosition !== null) {
    // 3. 把读取到的字符串转回数字
    const positionToScrollTo = parseInt(savedPosition, 10);

    // 4. 关键一步:让浏览器窗口滚动到记录的位置!
    window.scrollTo(0, positionToScrollTo); // (x坐标, y坐标)
  }
  // 如果没存过值(savedPosition是null),就什么也不做,让页面保持默认顶部位置
});

为什么用 window.load 确保页面所有元素都已渲染完成,再滚动位置才准确。如果使用 DOMContentLoaded(DOM 树构建完成触发),图片等未加载的内容可能导致最终高度变化,定位不准。

简单的DEMO

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>阅读位置记忆 Demo</title>
    <style>
        .long-content { height: 3000px; background: linear-gradient(#e66465, #9198e5); }
    </style>
</head>
<body>
    <h1>试试滚动我,然后刷新!</h1>
    <div class="long-content"></div>

    <script>
        // 1. 防抖计时器变量
        let scrollTimer = null;

        // 2. 监听滚动事件(带防抖)
        window.addEventListener('scroll', function() {
            clearTimeout(scrollTimer);
            scrollTimer = setTimeout(saveScrollPosition, 250); // 250ms后执行保存
        });

        // 3. 保存滚动位置到 sessionStorage
        function saveScrollPosition() {
            const scrollY = window.pageYOffset || document.documentElement.scrollTop;
            sessionStorage.setItem('lastKnownScrollPos', scrollY.toString());
            console.log('保存位置:', scrollY); // 调试用,实际可去掉
        }

        // 4. 页面加载时,尝试恢复位置
        window.addEventListener('load', function() {
            const savedPos = sessionStorage.getItem('lastKnownScrollPos');
            if (savedPos !== null) {
                const restorePos = parseInt(savedPos, 10);
                window.scrollTo(0, restorePos);
                console.log('恢复位置:', restorePos); // 调试用
            }
        });
    </script>
</body>
</html>

试试看:

  1. 打开这个页面。
  2. 随意滚动到某个地方。
  3. 刷新浏览器(按 F5 或浏览器刷新按钮)。
  4. 观察页面是否自动滚动回你上次停留的位置。魔法生效!

总结

实现"记住阅读位置"的功能,技术核心就是:监听滚动 -> 防抖节流 -> 存位置 (sessionStorage) -> 回来时读位置 -> 滚回去 (scrollTo)。代码量不大,对性能影响微乎其微,但为用户体验带来的提升却是巨大的。

下次当你开发包含长内容的页面时,花上半个小时,把这套"记忆魔法"集成进去,提高提高用户的体验度还是不错的。

相关推荐
傅里叶11 分钟前
Flutter在OrangePi 5 Plus上视频播放锁死问题
前端·flutter
古夕44 分钟前
my-first-ai-web_问题记录03——NextJS 项目框架基础扫盲
前端·javascript·react.js
曲意已决1 小时前
《深入源码理解webpac构建流程》
前端·javascript
去伪存真1 小时前
前端如何让一套构建产物,可以部署多个环境?
前端
KubeSphere2 小时前
EdgeWize v3.1.1 边缘 AI 网关功能深度解析:打造企业级边缘智能新体验
前端
掘金安东尼2 小时前
解读 hidden=until-found 属性
前端·javascript·面试
1024小神2 小时前
jsPDF 不同屏幕尺寸 生成的pdf不一致,怎么解决
前端·javascript
滕本尊2 小时前
构建可扩展的 DSL 驱动前端框架:从 CRUD 到领域模型的跃迁
前端·全栈
借月2 小时前
高德地图绘制工具全解析:线路、矩形、圆形、多边形绘制与编辑指南 🗺️✏️
前端·vue.js
li理2 小时前
NavPathStack 是鸿蒙 Navigation 路由的核心控制器
前端