【前端实战】如何让用户回到上次阅读的位置?

【前端实战】如何让用户回到上次阅读的位置?

目录

【前端实战】如何让用户回到上次阅读的位置?

一、总体思路

1、核心目标

2、涉及到的技术

二、实现方案详解

1、基础方法:监听滚动,记录 scrollTop(不推荐)

2、Intersection Observer + 插入探针元素

3、基于 URL Hash 锚点跳转

三、总结

1、不同方案间对比总结

2、结语


        作者:watermelo37

        ZEEKLOG万粉博主、华为云云享专家、阿里云专家博主、腾讯云、支付宝合作作者,全平台博客昵称watermelo37。

        一个假装是giser的coder,做不只专注于业务逻辑的前端工程师,Java、Docker、Python、LLM均有涉猎。



---------------------------------------------------------------------

温柔地对待温柔的人,包容的三观就是最大的温柔。

---------------------------------------------------------------------

【前端实战】如何让用户回到上次阅读的位置?

        在阅读类、资讯类、博客类网站中,记忆用户上次阅读到的位置,并在下次访问时自动滚动回那个位置,可以大大提升用户体验感。

        今天我们就来详细讲一讲:前端如何实现用户回到上次阅读的位置,包括基础scroll方法+优化、 Intersection Observer API + 探针追踪、锚点 URL HASH 定位跳转等策略实现一个流畅且高效的方案。

一、总体思路

1、核心目标

        在用户滚动时记录当前位置

        在页面重新加载时恢复到记录的位置

2、涉及到的技术

        可以根据下列技术进行知识补充,或者直接选择自己已经熟悉的技术来实现:

  • scroll 事件监听
  • localStorage 本地存储
  • requestAnimationFrame 节流优化
  • Intersection Observer API 观察元素进入视口
  • Vue3 响应式组件(如果需要框架版本)

二、实现方案详解

1、基础方法:监听滚动,记录 scrollTop(不推荐)

        在用户滚动时,实时记录 window.scrollY(页面滚动的垂直距离),保存到 localStorage 中。页面加载时,从 localStorage 读取,并 scrollTo 恢复。

        这可能是很多人的第一直觉,但是这种方法存在一个问题,就是scroll事件触发太频繁了。高频滚动下每秒触发一百多次都是非常正常的情况,常规的节流方法也不合适,比如添加一个节流时间。因为滚动可以是一个非常快速的过程,一秒钟可能可以操作滚动条从顶到尾。所以这里选择使用 requestAnimationFrame 方法来节流。

// 用于保存最新滚动位置 let lastKnownScrollY = 0; // 用于控制 requestAnimationFrame let ticking = false; // 监听滚动事件 window.addEventListener('scroll', () => { lastKnownScrollY = window.scrollY; // 防止过度频繁存储,使用requestAnimationFrame节流 if (!ticking) { window.requestAnimationFrame(() => { // 将滚动位置保存在localStorage中 localStorage.setItem('scrollPosition', lastKnownScrollY); ticking = false; }); ticking = true; } }); // 页面加载时,恢复之前保存的位置 window.addEventListener('DOMContentLoaded', () => { const savedPosition = localStorage.getItem('scrollPosition'); if (savedPosition !== null) { window.scrollTo(0, parseInt(savedPosition)); } }); 
        requestAnimationFrame 是浏览器提供的用于执行高效动画的 API,它会在下一次重绘前调用指定的回调函数,确保动画与屏幕刷新率同步(通常为 60Hz),从而实现平滑、流畅的视觉效果,同时避免不必要的性能开销。

        它的执行频率比 scroll 要小一些,同时不滚动的时候也不会触发,相比与 scroll 的高频触发,起到了一个节流效果。

2、Intersection Observer + 插入探针元素

        Intersection Observer在确定页面位置的时候有奇效,效率比scroll事件监听高了不止一星半点,但是如果存在大块、不宜分割或者杂乱的元素,那么监听元素的选择就会成为一个问题。

        添加探针元素可以有效解决这个问题,探针元素只需要小小一个 div,可以设置为 visibility: hidden,不影响页面布局。他们就像一个个哨兵,负责观察你的视口到了什么位置。

        (1)页面插入探针元素

        可以在重要段落、章节、标题前插入隐形的小 div。

<article> <div></div> <h2>第一章 标题</h2> <p>正文内容...</p> <div></div> <h2>第二章 标题</h2> <p>正文内容...</p> <!-- 更多内容 --> </article> 

        (2)设置 Intersection Observer,并在页面加载时,滚动到探针位置

// 创建 IntersectionObserver 实例 const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { // 如果探针元素进入可视区,记录它的id localStorage.setItem('lastVisibleSectionId', entry.target.id); } }); }, { threshold: 0.5 // 元素至少50%可见时触发 }); // 监听所有探针元素 document.querySelectorAll('.observer-marker').forEach(marker => { observer.observe(marker); }); // 页面加载时,恢复到上次记录的探针 window.addEventListener('DOMContentLoaded', () => { const lastId = localStorage.getItem('lastVisibleSectionId'); if (lastId) { const element = document.getElementById(lastId); if (element) { element.scrollIntoView({ behavior: 'smooth' }); // 平滑滚动到探针 } } }); 

3、基于 URL Hash 锚点跳转

        给每一节内容设置唯一 id,用户阅读到某个位置时,自动更新 URL 的 hash(锚点 #id),页面加载时,浏览器根据 hash 自动滚动到对应位置。这种方式实现的跳转甚至可以实现分享,因为位置信息是保存在 URL 里面的。

        是不是很熟悉?ZEEKLOG的目录跳转就是这么实现的。

// 监听页面滚动,动态更新 URL Hash const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { // 动态替换地址栏 hash,不刷新页面 history.replaceState(null, '', `#${entry.target.id}`); } }); }, { threshold: 0.5 }); // 监听所有需要作为锚点的元素 document.querySelectorAll('.observer-marker').forEach(marker => { observer.observe(marker); }); // 页面刷新后,浏览器会自动滚动到hash对应的元素 

三、总结

1、不同方案间对比总结

方法优点缺点适用场景

scrollTop 记录

通用、简单粗糙、动态内容页面误差大小型项目、静态页面
Intersection Observer 探针精准、性能好要布置探针,稍复杂长内容、章节型页面
URL Hash 锚点轻便、天然支持浏览器跳转地址栏变化,需考虑SEO文章分享、文档导航

2、结语

        实现回到上次阅读位置,并不只有一种方式,关键是根据你的项目特点选择:

  • 内容简单 ➔ scrollTop 就够了。
  • 内容结构清晰 ➔ Intersection Observer是最佳。
  • 需要分享/跳转 ➔ 用 URL Hash 最自然。

        总之,真正优秀的细节体验,源自对用户行为的深刻理解和用心打磨。

        只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

        其他热门文章,请关注:

        极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图

        你真的会使用Vue3的onMounted钩子函数吗?Vue3中onMounted的用法详解

        DeepSeek:全栈开发者视角下的AI革命者

        通过array.filter()实现数组的数据筛选、数据清洗和链式调用

        通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能

        TreeSize:免费的磁盘清理与管理神器,解决C盘爆满的燃眉之急

        通过MongoDB Atlas 实现语义搜索与 RAG——迈向AI的搜索机制

        深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解

        el-table实现动态数据的实时排序,一篇文章讲清楚elementui的表格排序功能

        前端实战:基于Vue3与免费满血版DeepSeek实现无限滚动+懒加载+瀑布流模块及优化策略

        MutationObserver详解+案例——深入理解 JavaScript 中的 MutationObserver

        JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、DOM操作等

        高效工作流:用Mermaid绘制你的专属流程图;如何在Vue3中导入mermaid绘制流程图

        干货含源码!如何用Java后端操作Docker(命令行篇)

        在线编程实现!如何在Java后端通过DockerClient操作Docker生成python环境

        Dockerfile全面指南:从基础到进阶,掌握容器化构建的核心工具

Read more

Flutter 组件 graphql 的适配 鸿蒙Harmony 实战 - 驾驭标准化分布式图形协议、实现鸿蒙端实时订阅与高性能交互网关方案

Flutter 组件 graphql 的适配 鸿蒙Harmony 实战 - 驾驭标准化分布式图形协议、实现鸿蒙端实时订阅与高性能交互网关方案

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 graphql 的适配 鸿蒙Harmony 实战 - 驾驭标准化分布式图形协议、实现鸿蒙端实时订阅与高性能交互网关方案 前言 在鸿蒙(OpenHarmony)生态的万物互联、极繁交互中台、以及对数据获取灵活性有极致要求的现代应用研发中,“高效的数据检索协议”是应用响应速度的灵魂。面对复杂的社交网络关系查询、实时的行情推送、或是海量状态信息的聚合。如果仅仅依靠传统的 RESTful 接口,那么不仅会导致因为 Over-fetching(获取多余数据)导致的带宽浪费,更会因为频繁的 API 版本演进引入严重的跨端兼容性碎片化问题。 我们需要一种“按需检索、逻辑解耦”的交互艺术。 graphql 是一套专为 Flutter 设计的标准 GraphQL 客户端套件。它通过构建规范的规范化缓存(Normalized Cache)与极其灵活的连接链路(Links)

By Ne0inhk
FARS全自动科研系统技术深度解析:从多智能体架构到工业化科研范式

FARS全自动科研系统技术深度解析:从多智能体架构到工业化科研范式

前言 2026年2月12日至2月22日,一场持续228小时33分钟的直播在全球AI社区引发了持续震荡。屏幕另一端,一个名为FARS(Fully Automated Research System)的全自动研究系统,在没有人类干预的情况下,自主完成了从文献调研到论文撰写的完整科研流程,最终产出100篇学术论文,总消耗114亿Token,成本10.4万美元。 这场实验的意义远不止于“AI写论文”的简单升级。它向世界展示了科学发现的根本范式正在发生转移——从依赖人类灵感的“手工作坊”,转向由AI驱动的“工业化流水线”。本文将从最底层的技术细节出发,逐层拆解FARS的系统架构、智能体协作机制、资源调度策略、成本控制模型,以及与竞品的技术对比,为读者呈现一个完整的全自动科研系统技术图谱。 第一章 系统总体架构:四智能体流水线设计 1.1 核心设计理念:研究系统的第一性原理 FARS的设计并非简单地模仿人类科研流程,而是基于团队对“研究系统”本质的重新思考。创始团队提出,一个理想的研究系统应遵循两条基本原则: 1. 高效拓展知识边界:系统的吞吐量应成为核心评估指标,而非单篇论文的完

By Ne0inhk
基于Java和高德开放平台的WebAPI集成实践-以搜索POI2.0为例

基于Java和高德开放平台的WebAPI集成实践-以搜索POI2.0为例

目录 前言 一、高德搜索API简介 1、高德开放平台 2、搜索功能介绍  3、部分API介绍 二、Uniapi集成高德API 1、API集成流程 2、访问接口的定义 3、业务调用集成 三、常见问题与优化 四、总结 前言         在当今数字化时代,地理信息系统(GIS)和位置服务(LBS)已成为许多应用程序的核心组成部分。无论是导航、物流、社交网络还是电子商务,位置数据的获取和处理都显得尤为重要。高德开放平台作为国内领先的地理信息服务提供商,提供了丰富的WebAPI接口,帮助开发者快速集成地图、导航、搜索等功能。其中,POI(Point of Interest)搜索是许多应用场景中的关键功能,它能够帮助用户快速找到附近的兴趣点,如餐馆、酒店、加油站等。         Java作为一种广泛使用的编程语言,因其跨平台性、

By Ne0inhk
字节跳动 Eino 框架(Golang+AI)知识点全面总结

字节跳动 Eino 框架(Golang+AI)知识点全面总结

一、框架核心定位与目标 Eino 是字节跳动面向 AI 工程化落地 的开源框架,基于 Golang 的高并发、易部署特性,解决 AI 应用从 “单机原型” 到 “分布式生产级服务” 的核心痛点: * 降低分布式 AI 应用的开发复杂度(无需手动处理集群调度、模型分发、负载均衡); * 打通 “模型训练 → 模型部署 → 推理服务” 全链路,提供统一工具链; * 适配主流 AI 框架(TensorFlow、PyTorch、ONNX)和云原生环境(K8s、Docker); * 兼顾性能与灵活性,支持单机轻量部署和大规模集群扩展。 核心目标:让 Golang 开发者无需深入 AI 分布式原理,即可快速构建高性能、高可用的 AI

By Ne0inhk