问题描述
Here 我复制了一个简单的片段,其中包含使用 react-spring
进行的页面转换。
有没有办法在点击浏览器后退按钮时恢复上一页滚动位置?
周围有很多相关的QA,但是在使用动画库时找不到任何解决方案
知道如何实现这一目标吗?
解决方法
导航时恢复 scrollY 位置并不容易。我们可能需要一个上下文来存储页面的 y 位置。以下是我的解决方案。
用于监听滚动事件的自定义钩子(hooks/scroll.js)
import { useEffect,useState } from 'react';
import { useLocation } from 'react-router-dom';
export const useScrollPositions = () => {
const [positions,setPositions] = useState(new Map());
const location = useLocation();
useEffect(() => {
const listener = (ev) => {
console.log('position: ',ev.target.scrollTop);
positions.set(location.pathname,{
left: ev.target.scrollLeft,top: ev.target.scrollTop
});
setPositions(new Map(positions));
}
window.addEventListener('scroll',listener,true);
return () => {
window.removeEventListener('scroll',true);
}
},[location]);
return positions;
}
用于存储页面 y 位置的上下文(context/scroll-context.js)
import { createContext } from 'react';
export const ScrollContext = createContext();
将所有页面包装在上下文提供程序中:应用组件
const App = () => {
const location = useLocation();
const positions = useScrollPositions();
const transitions = useTransition(location,{
from: { opacity: 0,transform: 'translate3d(100vw,0)' },enter: { opacity: 1,transform: 'translate3d(0,leave: { opacity: 0,transform: 'translate3d(-20vw,});
return (
<ScrollContext.Provider value={positions}>
<GlobalStyles />
<Switch>
<Route path='/' exact component={Home} />
<Route path="/about" component={About} />
</Switch>
{transitions((props,item) => (
<animated.div style={props}>
<Switch location={item}>
<Route path="/" exact component={Home} />
<Route path="/about" exact component={About} />
</Switch>
</animated.div>
))}
</ScrollContext.Provider>
);
};
滚动页面组件
import React,{ useEffect,useRef,useContext } from 'react';
import { useLocation } from 'react-router-dom';
import { ScrollContext } from '../context/scroll-context';
const Page = ({children,...rest}) => {
const main = useRef();
const positions = useContext(ScrollContext);
const location = useLocation();
useEffect(() => {
if (main.current) {
const position = positions.get(location.pathname);
if (position && position.top) {
main.current.scrollTop = position.top;
}
}
},[])
return (
<main {...rest} ref={main}>
{children}
</main>
)
}
export default Page
注意:您必须将所有页面都包装在此页面组件中。这个页面组件的 CSS 样式(scroll: auto)也很重要。在现实世界的项目中,它可能需要更灵活的代码。无论如何,对于一个完整的工作项目,请检查 here
,您可以在卸载组件时调用以下方法并保留它。
export const getScrollPage = (): number => {
let docScrollTop = 0;
if (document.documentElement && document.documentElement !== null) {
docScrollTop = document.documentElement.scrollTop;
}
return window.pageYOffset || docScrollTop;
};
使用保留的滚动 y 位置值并传递给下面的函数。
export const scrollTo = (scrollnumber: number = 0): number =>
window.requestAnimationFrame(() => {
window.scrollTo(0,scrollnumber);
});