在 Vue 项目中保持滚动位置

25 min read

在 Vue 项目中保持滚动位置

在使用 Vue 和 Vue Router 构建的单页面应用(SPA)中,维持用户在页面间导航时的滚动位置是提升用户体验的重要方面。下面是关于如何实现和管理滚动位置保持的综合指南。

使用 Vue Router 的 scrollBehavior 方法

Vue Router 提供了一个 scrollBehavior 方法,用于处理路由跳转时页面滚动行为的自定义。

const router = createRouter({
    history: createWebHistory("/"),
    scrollBehavior(to, from, savedPosition) {
        if (savedPosition) {
            return savedPosition;
        } else {
            return { top: 0 };
        }
    },
    routes: [...]
});

监听滚动事件并保存滚动位置

为了记住特定页面的滚动位置,尤其是在 keep-alive 组件缓存的情况下,你需要手动监听滚动事件并保存滚动位置。

方法一:使用全局状态管理或全局变量
  1. 创建全局变量或状态:使用 Vuex 或简单的全局对象来存储滚动位置。
  2. 在路由守卫中保存和恢复滚动位置
// 假设有一个全局状态管理或简单的全局对象
const scrollPositions = {};

// 保存滚动位置
router.beforeEach((to, from, next) => {
    if (from.meta.keepAlive) {
        const $wrapper = document.querySelector('.app-container__content');
        if ($wrapper) {
            scrollPositions[from.path] = $wrapper.scrollTop;
        }
    }
    next();
});

// 恢复滚动位置
router.afterEach((to) => {
    Vue.nextTick(() => {
        const $wrapper = document.querySelector('.app-container__content');
        if ($wrapper && scrollPositions[to.path] !== undefined) {
            $wrapper.scrollTop = scrollPositions[to.path];
        }
    });
});
方法二:直接修改路由的 meta 字段

直接在 beforeEach 守卫中修改 from.meta 来保存滚动位置,然后在合适的时机恢复它。这种方法虽然简单,但不推荐,因为它违反了不可变数据原则,且在页面刷新或组件复用方面存在局限。

注意事项

  • 组件复用问题:确保处理好 <keep-alive> 缓存的组件在复用时的滚动位置。
  • 性能考虑:监听滚动事件可能会影响性能,尤其是在滚动操作非常频繁的情况下。确保适当地防抖或节流你的滚动事件处理函数。
  • 页面刷新问题:使用全局状态管理或全局变量的方法能够在一定程度上在页面刷新后保持滚动位置,但需要注意状态管理的持久化。