存在一个场景:
在列表页滚动查看某一条卡片时,从卡片进入详情页面后,返回时希望页面能够滚动回原来的卡片位置,而不是顶部或其他位置。应该怎么办呢?
1. 方法简述
1.1 整体流程
- 离开页面时:
- 记录当前滚动位置。
- 返回页面时:
- 判断是否需要刷新数据和还原滚动位置。
- 如果需要:
- 调用指定的刷新方法。
- 将滚动位置还原到离开时的值。
1.2 核心处理
import { computed, ref } from 'vue';
export default function useRefreshScroll({fromList,scrollDomRef,queryDomRef = null,queryFn = 'onRefresh',
}) {// 存储离开时的位置const preScrollTop = ref(0);const scrollDom = computed(() => (scrollDomRef.value instanceof HTMLElement ? scrollDomRef.value : scrollDomRef.value?.$el));// 页面进入前判断是否需要还原位置const beforeEnter = async (to, from, next) => {if (fromList.includes(from.name as string)) {const resultQueryDomRef = queryDomRef ?? scrollDomRef;const refreshFn = resultQueryDomRef.value?.[queryFn];if (refreshFn) {await refreshFn();}setTimeout(() => {if (scrollDom.value) {scrollDom.value.scrollTop = preScrollTop?.value;}}, 300); // 观感考虑设置为300}next();};// 记录离开时的位置 scrollTopconst beforeLeave = (to, from, next) => {preScrollTop.value = scrollDom?.value?.scrollTop ?? 0;next();};return {beforeLeave,beforeEnter,};
}
1.3 具体使用方法
<template><div ref="scrollDomRef" class="scroll-container"><!-- 这里是滚动内容 --></div>
</template><script>
import { ref } from 'vue';
import useRefreshScroll from './path/to/useRefreshScroll';export default {name: 'MyComponent',setup() {const scrollDomRef = ref(null); // 滚动容器的 refconst { beforeLeave, beforeEnter } = useRefreshScroll({// 假设从 'home' 或 'profile' 页面跳转过来时需要恢复滚动位置fromList: ['home', 'profile'],scrollDomRef,queryFn: 'onRefresh',});// 这里可以处理路由守卫...return {scrollDomRef,beforeLeave,beforeEnter,};},
};
</script>
2. 方法介绍
作用:根据条件判断是否需要刷新页面数据,并将页面滚动位置恢复到离开时的锚点位置。
参数如下:
/*** @param fromList:Array<string>,页面导航的前置页面 name 列表。如果从这些页面返回,则触发数据刷新和滚动位置恢复逻辑。* @param scrollDomRef:Ref,表示滚动容器的引用,可能是一个 DOM 节点或 Vue 组件实例。* @param queryDomRef:Ref,用于调用数据刷新方法的组件引用,默认值是 scrollDomRef。* @param queryFn:string,需要调用的刷新数据的方法名称,默认是 'onRefresh'。* @return {*}*/
部分代码注释:
1、scrollDom:返回滚动容器的实际 DOM 元素。如果 scrollDomRef.value 是一个 DOM 元素,则直接返回,如果其是 Vue 组件实例,则尝试获取根 DOM 元素(使用 $el )。
const scrollDom = computed(() => (scrollDomRef.value instanceof HTMLElement ? scrollDomRef.value : scrollDomRef.value?.$el)
);
2、beforeEnter 和 beforeLeave Vue Router 的路由守卫
在 beforeEnter 中,首先检查页面是否从某个特定页面(由 fromList 定义)跳转过来。如果是的话,它会检查是否需要执行 onRefresh 等操作,并且在视图渲染后恢复滚动位置。
在 beforeLeave 中,记录了当前页面的滚动位置 scrollTop,以便在进入下一个页面时恢复这个位置。
这两个方法会在 Vue Router 的生命周期钩子 beforeRouteEnter、beforeRouteLeave 中使用。
3、next() 是 Vue Router 生命周期钩子中的回调函数,用来继续路由的生命周期。
eg:在 beforeEnter 和 beforeLeave 调用,通知 Vue Router 继续执行路由切换操作。
总结:
通过 Vue 的响应式 API 和导航守卫,实现了动态刷新与滚动位置恢复的功能,更好的提升用户体验。