恢复滚动 y 位置 react-router-dom

问题描述

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);
  });

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...