vue3+ts实现页面滚动位置的保存及恢复

前言:

折腾了n个小时才搞定,这个在vue2中不显眼的功能到了vue3中没想到成为了拦路虎。借助于AI一遍一遍的尝试各种方案,最终敲定了路由守卫beforeEach中保存组件滚动位置到store,页面的onActivated中读取滚动位置并进行恢复。

实现思路:

路由守卫beforeEach中保存滚动位置——页面onActivated声明周期中恢复滚动位置。

关键代码:

1. 编写store保存页面滚动位置:

scrollStore.ts

import { defineStore, createPinia } from "pinia";
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";

// 第一步:创建 Pinia 实例
const pinia = createPinia();
// 第二步:注册持久化插件(必须在定义 Store 之前)
pinia.use(piniaPluginPersistedstate);
// 第三步:导出pinia
export default pinia;

//页面滚动状态保持
export const useScrollStore = defineStore("scrollStore", {
  state: () => {
    return {
      scrollTop: 0,
    };
  },
  //数据持久化配置
  persist: {
    storage: sessionStorage,
  },
  actions: {
    updateScrollTop(data) {
      console.log(data);
      this.scrollTop = data;
    },
  },
});

2. 路由守卫beforeEach中保存组件滚动位置到store:

router.ts

import { createRouter, createWebHashHistory } from "vue-router";
import { useScrollStore } from "@/store/index";

const routerHash = createWebHashHistory();

const router = createRouter({
  history: routerHash,
  routes: [
    {
      path: "/",
      name: "Home",
      meta: {
        keepAlive: true,
        showTabbar: true,
        saveScroll: true,
      },
      component: () => import("@/views/Home.vue"),
    },
    {
      path: "/:w+",
      name: "Error",
      meta: {
        title: "访问错误",
      },
      component: () => import("@/views/Error.vue"),
    },
  ],
});

router.beforeEach((to, from) => {
  /* 路由发生变化修改页面title */
  const title: any = to.meta && to.meta.title;
  if (title) {
    document.title = title;
  } else {
    document.title = "积分商城";
  }
  // 保存滚动位置
  if (from.meta?.saveScroll) {
    const scrollStore = useScrollStore();
    // 注意:路由守卫中需确保 DOM 已渲染,直接用 window.scrollY 或自定义容器 scrollTop
    const scrollTop = document.getElementById("container").scrollTop; // 若为自定义容器,需通过 document 获取 DOM
    scrollStore.updateScrollTop(scrollTop);
  }
});

export default router;

3. 封装恢复滚动位置的代码:

useScroll.ts

import { onActivated } from "vue";
import { useScrollStore } from "../store/index";

export default function useScroll() {
  const scrollStore = useScrollStore();

  // 组件激活时恢复滚动位置
  onActivated(() => {
    const savedTop = scrollStore.scrollTop;
    const container = document.getElementById("container");
    if (container && savedTop > 0) {
      // 激活时直接赋值,无延迟
      container.scrollTop = savedTop;
    }
  });
}

封装后就方便在多个页面中直接使用了。

4. 页面引入:

需要保持页面滚动位置的页面只需引入 useScroll,无需额外代码

<template>
  <div id="container">
    <!--页面内容-->
  </div>
</template>

<script setup lang="ts">
  import { useScroll} from '@/store/useScroll'
  useScroll()</script>

<style lang="scss" scoped>
  #container {
    height: calc(100vh - 100px);
    overflow-y: scroll;
  }
</style>

如上,即可实现页面滚动位置保存及恢复功能,实测有效,如果遇到没生效的可以留言代码交流。

posted on 2025-11-12 17:18  逍遥云天  阅读(25)  评论(0)    收藏  举报

导航