西安网站建设推广专家,ngrok 群晖wordpress,重庆建设公司网站,网站建设属于什么行业类别目录
【前端实战】如何让用户回到上次阅读的位置#xff1f;
一、总体思路
1、核心目标
2、涉及到的技术
二、实现方案详解
1、基础方法#xff1a;监听滚动#xff0c;记录 scrollTop#xff08;不推荐#xff09;
2、Intersection Observer 插入探针元素
3、基…目录
【前端实战】如何让用户回到上次阅读的位置
一、总体思路
1、核心目标
2、涉及到的技术
二、实现方案详解
1、基础方法监听滚动记录 scrollTop不推荐
2、Intersection Observer 插入探针元素
3、基于 URL Hash 锚点跳转
三、总结 1、不同方案间对比总结
2、结语 作者watermelo37 CSDN万粉博主、华为云云享专家、阿里云专家博主、腾讯云、支付宝合作作者全平台博客昵称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。
articlediv idsection-1 classobserver-marker/divh2第一章 标题/h2p正文内容.../pdiv idsection-2 classobserver-marker/divh2第二章 标题/h2p正文内容.../p!-- 更多内容 --
/article2设置 Intersection Observer并在页面加载时滚动到探针位置
// 创建 IntersectionObserver 实例
const observer new IntersectionObserver((entries) {entries.forEach(entry {if (entry.isIntersecting) {// 如果探针元素进入可视区记录它的idlocalStorage.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 里面的。 是不是很熟悉CSDN的目录跳转就是这么实现的。
// 监听页面滚动动态更新 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全面指南从基础到进阶掌握容器化构建的核心工具