react -- 路由前进滚动到顶部,路由后退返回原来位置

919 阅读2分钟

路由前进滚动到顶部,路由后退返回原来位置

实现代码

function useReStoreMangerScroll({history}: RouteComponentProps){
    const { pathname } = useLocation()
    useEffect(() => {
        if(history.action == 'PUSH'){
            window.scrollTo(0, 0)
        }
        if(history.action == 'POP'){
            const restScroll = () => {
                window.scrollTo(0 , +(sessionStorage.getItem(pathname || '') || 0))
            }
            for(let n of [0, 30, 50, 80, 100, 200, 300, 400, 500, 600]){
                setTimeout(restScroll, n)
            }
        }
        return () => {
            sessionStorage.setItem(pathname, window.scrollY.toString())
        }
    }, [])
}
上面有几个枚举值,看起来不太好看,不过我觉得蛮通用的,因为我们总不能去请求结束后来一个回调,这样太麻烦了。

然后再弄到页面里面即可,但是我们也不能每个都写,弄成中间件即可,如图

我们在上面的代码中用了延迟是因为页面的数据可能是动态加载的,这时候点击返回俺就后浏览器会自动先滚动上次的位置(上次记录的值),但是数据还没有加载出来,这时候等最后数据加载出来并渲染完成的时候,并不会再一次转跳,因为转跳过一次了,这时候有一个差值,所以页面看起来会有点怪怪的,后退后不是滚动到理想的位置上。

从这里可以看出来,浏览器自动设置值对于动态页面并没有实际用处,我们可以先不要浏览器自动设置值, 把它关闭

if (history.scrollRestoration) {
  history.scrollRestoration = 'manual';
}

还有一个问题就是,会有闪烁的一瞬间,这个是无法避免的,因为数据是动态加载的,但是也不是没有解决方案,既然数据是动态加载导致没数据,那么我们缓存下数据不就解决了,比如google搜索,但是我们就是动态的啊,就是要刷新,这时候可以先设置回来原来的值然后再去加载新数据,这样就没有闪动了。但是这样无法简单的插件解决,所以只能修改下架构或者不做这个功能。(我们国内大部分产品从一级页面到二级页面都是直接打开一个新的标签~~)

--完--