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

前言:

折腾了n个小时才搞定,这个在vue2中不显眼的功能到了vue3中没想到成为了拦路虎。借助于AI一遍一遍的尝试各种方案,最终敲定了路由scrollBehavior保存组件滚动位置到pinia,页面的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. 使用scrollBehavior保存滚动位置到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,
        saveScroll: true,
      },
      component: () => import("@/views/Home.vue"),
    },
    {
      path: "/:w+",
      name: "Error",
      meta: {
        title: "访问错误",
      },
      component: () => import("@/views/Error.vue"),
    },
  ], // 关键:覆盖默认滚动行为,阻止路由切换时自动滚顶
  scrollBehavior: (to, from, savedPosition) => {
    // 1. 若从需要保存滚动的页面(from.meta.saveScroll)跳转,优先恢复滚动
    if (to.meta.saveScroll) {
      const scrollStore = useScrollStore();
      const savedTop = scrollStore.scrollTop;
      if (savedTop > 0) {
        // 用 nextTick 确保 DOM 已渲染,比 setTimeout(0) 更快
        return nextTick().then(() => {
          const container = document.getElementById("container");
          if (container) {
            return {
              el: "#container", // 指定滚动容器
              top: savedTop, // 恢复到保存的位置
              behavior: "smooth", // 默认为瞬间滚动(无动画,避免闪动)
            };
          }
        });
      }
    }
    // 2. 其他页面默认滚顶(可根据需求调整)
    return { top: 0 };
  },
});
export default router;

3. 页面引入:
需要保持页面滚动位置的页面只需引入 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:17  逍遥云天  阅读(0)  评论(0)    收藏  举报

导航