在前端实战中,“让用户回到上次阅读的位置”是提升用户体验的常见功能,尤其适用于以下场景:

  • 📚 阅读类网页(小说、博客、新闻)
  • 📋 管理系统长列表页
  • 🔄 页面刷新后恢复浏览状态

✅ 实现原理概览

核心思想是:

监听页面滚动位置并保存 → 页面加载时读取并恢复。

实现步骤如下:


📌 一、原生 JavaScript 实现方案

1️⃣ 保存滚动位置到本地(localStorage

window.addEventListener('scroll', () => {
  const scrollY = window.scrollY || document.documentElement.scrollTop;
  localStorage.setItem('scrollPosition', scrollY);
});

建议搭配节流 throttle(例如 lodash)防止频繁写入。


2️⃣ 页面加载时恢复滚动位置

window.addEventListener('load', () => {
  const savedPosition = parseInt(localStorage.getItem('scrollPosition') || '0');
  window.scrollTo(0, savedPosition);
});

✅ 可用 setTimeout(() => window.scrollTo(...)) 延迟恢复,解决内容未加载完问题。


🔧 二、Vue3 实现(Composition API)

import { onMounted, onBeforeUnmount } from 'vue';

export default {
  setup() {
    const saveScroll = () => {
      const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
      localStorage.setItem('vue-scroll-top', scrollTop.toString());
    };

    onMounted(() => {
      const pos = parseInt(localStorage.getItem('vue-scroll-top') || '0');
      window.scrollTo(0, pos);
      window.addEventListener('scroll', saveScroll);
    });

    onBeforeUnmount(() => {
      window.removeEventListener('scroll', saveScroll);
    });
  }
};

📦 三、React 实现(自定义 Hook)

import { useEffect } from 'react';

export function useScrollRestore(key = 'scroll-position') {
  useEffect(() => {
    const scrollY = localStorage.getItem(key);
    if (scrollY) {
      window.scrollTo(0, parseInt(scrollY));
    }

    const handler = () => {
      localStorage.setItem(key, window.scrollY.toString());
    };

    window.addEventListener('scroll', handler);
    return () => window.removeEventListener('scroll', handler);
  }, []);
}

🌐 四、根据页面唯一性保存位置

多页面/多文章的阅读位置要分别保存,可使用 URL 或文章 ID 作为 Key:

const key = `scroll-${location.pathname}`;
localStorage.setItem(key, window.scrollY);

⚠️ 注意事项

问题建议处理方式
页面内容未加载完就滚动失败使用 setTimeout() 或监听图片/异步加载完后再滚动
频繁写入 LocalStorage用 lodash.throttle() 每 300ms 存储一次
动态路由场景使用 Vue Router/React Router 的 beforeRouteLeave 保存状态
hash 路由若已有锚点滚动,可避免自动滚动冲突

💡 Bonus:使用 sessionStorage 临时保存(浏览器关闭清除)

sessionStorage.setItem('scroll', window.scrollY);

适合不需要持久保存的临时记录场景。


✨ 效果演示逻辑

  1. 用户阅读一半刷新页面
  2. 页面重新加载时自动跳到之前的位置
  3. 打开新页面则从顶部开始,不冲突

✅ 总结一句话

“离开时记得位置,回来时不迷路”——这是提升用户体验的黄金法则之一。