Vue3 + Keep-Alive:实习中遇到的 window 滚动问题与实践

Vue3 + Keep-Alive:实习中遇到的 window 滚动问题与实践

前景:实习项目中的困扰

在实习期间,我参与了公司项目的前端开发,页面主要包括首页(Home)和探索页(Explore)。在项目中,这两个页面都使用 window 作为滚动容器。测试时发现一个问题:

javascript 复制代码
首页和探索页都使用 window 作为滚动容器
↓
它们共享同一个 window.scrollY(全局变量)
↓
用户在探索页滚动到 500px
↓
window.scrollY = 500(全局状态)
↓
切换到首页(首页组件被缓存,状态保留)
↓
但 window.scrollY 仍然是 500(全局共享)
↓
首页显示时,看起来也在 500px 的位置 ❌

这个问题的原因在于:

  • <keep-alive> 只缓存组件实例和 DOM,不管理滚动状态。
  • window.scrollY 是全局浏览器状态,不会随组件缓存自动恢复。
  • 结果就是组件被缓存后,滚动位置被错误共享,导致用户体验不佳。

我的思路:滚动位置管理工具

为了在自己的项目中解决类似问题,我考虑了手动管理滚动位置的方案:

javascript 复制代码
/**
 * 滚动位置管理工具
 * 用于在 keep-alive 缓存页面时,为每个路由独立保存和恢复滚动位置
 */
const scrollPositions = new Map()

export function saveScrollPosition(routePath) {
  const y = window.scrollY || document.documentElement.scrollTop || document.body.scrollTop
  scrollPositions.set(routePath, y)
}

export function restoreScrollPosition(routePath, defaultY = 0) {
  const saved = scrollPositions.get(routePath) ?? defaultY
  requestAnimationFrame(() => {
    window.scrollTo(0, saved)
    document.documentElement.scrollTop = saved
    document.body.scrollTop = saved
  })
}

在组件中配合 Vue 生命周期钩子使用:

javascript 复制代码
import { onActivated, onBeforeUnmount } from 'vue'
import { useRoute } from 'vue-router'
import { saveScrollPosition, restoreScrollPosition } from './scrollManager'

export default {
  setup() {
    const route = useRoute()

    // 组件激活时恢复滚动
    onActivated(() => {
      restoreScrollPosition(route.path, 0)
    })

    // 组件离开前保存滚动
    onBeforeUnmount(() => {
      saveScrollPosition(route.path)
    })
  }
}

公司项目的简化处理

在公司项目中,由于页面结构简单,不需要为每个路由保存独立滚动位置,因此我采用了统一重置滚动到顶部的方式:

javascript 复制代码
// 路由切换后重置滚动位置
router.afterEach((to, from) => {
  if (to.path !== from.path) {
    setTimeout(() => {
      window.scrollTo(0, 0)
      document.documentElement.scrollTop = 0
      document.body.scrollTop = 0
    }, 0)
  }
})

这样可以保证:

  • 切换页面时始终从顶部开始。
  • 简单易维护,符合公司项目需求。
  • 避免了 Keep-Alive 缓存滚动穿透的问题。

总结

  1. <keep-alive> 缓存组件实例,但不管理 window 滚动状态,导致全局滚动共享问题。
  2. 自己项目中,可以通过滚动位置管理工具为每个路由独立保存和恢复滚动。
  3. 公司项目中,为简化处理,只需在路由切换后重置滚动到顶部即可。
  4. 总体经验:滚动管理要根据项目复杂度和需求选择方案,既保证用户体验,又保证可维护性。
相关推荐
暴走的小呆17 小时前
Vue 2 中 Object 的变化侦测:从 getter/setter 到 Dep、Watcher、Observer
vue.js
英勇无比的消炎药17 小时前
TinyVue v-auto-tip: 文本超长自动提示的优雅方案
vue.js
时光足迹19 小时前
腾讯云 TRTC UniApp SDK 从入门到上线
前端·vue.js·uni-app
时光足迹20 小时前
uni-app 里把加密视频嵌入页面播放?我分析了 4 种方案,只有 1 种接近完美
前端·vue.js·uni-app
时光足迹20 小时前
JPush UniApp UTS 插件完全参考手册:API、事件与厂商通道一网打尽
vue.js·ios·uni-app
时光足迹20 小时前
极光推送全攻略(下):uni-app 代码实现与 iOS 排查实战
vue.js·ios·uni-app
疯狂的魔鬼21 小时前
一个"懂分寸"的文本省略组件是怎样炼成的
前端·vue.js·设计
裕波21 小时前
AI 正在重写应用开发。Vue 与 Vite,给出新的答案。
javascript·vue.js
妙码生花21 小时前
现代前端的极致性能 icon 加载方案(死磕成功版)
前端·vue.js·typescript
用户2136610035721 天前
Vue2脚手架工程化与Axios集成
前端·vue.js