vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue 滚动位置恢复

Vue页面返回滚动位置恢复(keep-alive滚动记忆)

作者:_AaronWong

Vue中通过自定义组合式函数useScroll,结合ref响应式状态、生命周期钩子及DOM引用,实现keep-alive缓存组件的滚动位置保存与恢复,优化用户返回时的浏览体验,感兴趣的可以了解一下

在Vue单页应用开发中,我们经常会遇到这样的场景:用户在一个长列表页面滚动浏览了若干项后,点击进入详情页,然后返回期望能够回到之前的滚动位置,而不是重新回到页面顶部。这种用户体验的优化对于内容型应用尤为重要。

Vue的<keep-alive>组件可以缓存页面状态,但它并不自动保存和恢复滚动位置。今天我们就来探讨一种优雅的解决方案。

核心代码解析

import { onActivated, ref } from "vue";
import { onBeforeRouteLeave } from "vue-router";

export function useScroll(targetRef) {
    const scrollTop = ref(0);
    
    onActivated(() => {
        if (targetRef.value) {
            targetRef.value.scrollTop = scrollTop.value
        }
    })
    
    onBeforeRouteLeave(() => {
        if (targetRef.value) {
            scrollTop.value = targetRef.value.scrollTop
        }
    })
}

这个自定义组合式函数useScroll虽然代码简洁,但功能强大且完整。让我们分解一下它的工作原理:

1. 响应式状态管理

使用ref(0)创建了一个响应式的scrollTop变量,用于存储滚动位置。

2. 生命周期钩子运用

3. 引用DOM元素

通过targetRef参数接收一个DOM元素的引用,这使得函数可以灵活应用于任何可滚动元素

完整使用示例

<template>
  <div class="product-list" ref="scrollTarget">
    <div v-for="product in products" :key="product.id" class="product-item">
      <h3>{{ product.name }}</h3>
      <p>{{ product.description }}</p>
      <button @click="goToDetail(product)">查看详情</button>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useScroll } from '@/composables/useScroll'

const router = useRouter()
const scrollTarget = ref(null)
const products = ref([...]) // 产品列表数据

// 使用滚动记忆功能
useScroll(scrollTarget)

const goToDetail = (product) => {
  router.push(`/product/${product.id}`)
}
</script>

<style scoped>
.product-list {
  height: 100vh;
  overflow-y: auto;
}
</style>

路由配置要点

为了使<keep-alive>生效,需要在路由配置和组件渲染中做相应设置:

// router.js
const routes = [
  {
    path: '/products',
    component: () => import('@/views/ProductsView.vue'),
    meta: { keepAlive: true } // 添加元信息标识需要缓存的页面
  }
  // ...其他路由
]
<!-- App.vue -->
<template>
  <router-view v-slot="{ Component, route }">
    <keep-alive>
      <component 
        :is="Component" 
        v-if="route.meta.keepAlive" 
        :key="route.name"
      />
    </keep-alive>
    <component 
      :is="Component" 
      v-if="!route.meta.keepAlive" 
      :key="route.name"
    />
  </router-view>
</template>

进阶优化

1. 多滚动容器支持

实际应用中,一个页面可能有多个滚动区域,我们可以扩展useScroll来支持这种情况:

export function useScroll(targetRef, identifier = 'default') {
    const scrollPositions = ref({});
    
    onActivated(() => {
        if (targetRef.value) {
            targetRef.value.scrollTop = scrollPositions.value[identifier] || 0;
        }
    })
    
    onBeforeRouteLeave(() => {
        if (targetRef.value) {
            scrollPositions.value[identifier] = targetRef.value.scrollTop;
        }
    })
}

2. 防抖处理

对于高频触发滚动事件的情况,可以添加防抖优化:

import { debounce } from 'lodash-es';

export function useScroll(targetRef) {
    const scrollTop = ref(0);
    
    onActivated(() => {
        if (targetRef.value) {
            targetRef.value.scrollTop = scrollTop.value;
        }
    })
    
    const saveScrollPosition = debounce(() => {
        if (targetRef.value) {
            scrollTop.value = targetRef.value.scrollTop;
        }
    }, 100);
    
    onMounted(() => {
        if (targetRef.value) {
            targetRef.value.addEventListener('scroll', saveScrollPosition);
        }
    });
    
    onUnmounted(() => {
        if (targetRef.value) {
            targetRef.value.removeEventListener('scroll', saveScrollPosition);
        }
    });
}

到此这篇关于Vue页面返回滚动位置恢复(keep-alive滚动记忆)的文章就介绍到这了,更多相关Vue 滚动位置恢复内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

您可能感兴趣的文章:
阅读全文