我有一个问题,当导航到另一个页面,它的位置将保持像之前的页面。所以它不会自动滚动到顶部。 我也试过使用window。onChange路由器上的scrollTo(0,0)。我还使用了scrollBehavior来修复这个问题,但它没有工作。对此有什么建议吗?


当前回答

因为,我使用功能组件,这里是我如何设法实现它。

import { useEffect } from 'react';
import { BrowserRouter, Routes, Route, useLocation } from 'react-router-dom';

function ScrollToTop() {
    const { pathname } = useLocation();

    useEffect(() => {
        window.scrollTo(0, 0);
    }, [pathname]);

    return null;
}

const IndexRoutes = () => {

    return (
        <BrowserRouter>
            <ScrollToTop />
            <Routes>
                <Route exact path="/">
                    <Home /> 
                </Route>
                /* list other routes below */
            </Routes>
        </BrowserRouter>
    );
};

export default IndexRoutes;

您也可以从下面的链接中参考代码

https://reactrouter.com/web/guides/scroll-restoration

其他回答

这个答案是遗留代码,对于路由器v4+检查其他答案

<Router onUpdate={() => window.scrollTo(0, 0)} history={createBrowserHistory()}>
  ...
</Router>

如果它不起作用,你应该找到原因。同样在componentDidMount内部

document.body.scrollTop = 0;
// or
window.scrollTo(0,0);

你可以用:

componentDidUpdate() {
  window.scrollTo(0,0);
}

你可以添加一些像" scrolling = false"这样的标志,然后在update中:

componentDidUpdate() {
  if(this.scrolled === false){
    window.scrollTo(0,0);
    scrolled = true;
  }
}

对于react-router v4,这里有一个实现滚动恢复的create-react-app: http://router-scroll-top.surge.sh/。

要实现这一点,你可以创建装饰Route组件和利用生命周期方法:

import React, { Component } from 'react';
import { Route, withRouter } from 'react-router-dom';

class ScrollToTopRoute extends Component {
  componentDidUpdate(prevProps) {
    if (this.props.path === this.props.location.pathname && this.props.location.pathname !== prevProps.location.pathname) {
      window.scrollTo(0, 0)
    }
  }

  render() {
    const { component: Component, ...rest } = this.props;

    return <Route {...rest} render={props => (<Component {...props} />)} />;
  }
}

export default withRouter(ScrollToTopRoute);

在componentDidUpdate上,我们可以检查位置路径名何时发生变化,并将其与路径道具匹配,如果满足,则恢复窗口滚动。

这个方法最酷的地方在于,我们可以有恢复滚动的路由和不恢复滚动的路由。

下面是一个App.js的例子,告诉你如何使用上面的方法:

import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import Lorem from 'react-lorem-component';
import ScrollToTopRoute from './ScrollToTopRoute';
import './App.css';

const Home = () => (
  <div className="App-page">
    <h2>Home</h2>
    <Lorem count={12} seed={12} />
  </div>
);

const About = () => (
  <div className="App-page">
    <h2>About</h2>
    <Lorem count={30} seed={4} />
  </div>
);

const AnotherPage = () => (
  <div className="App-page">
    <h2>This is just Another Page</h2>
    <Lorem count={12} seed={45} />
  </div>
);

class App extends Component {
  render() {
    return (
      <Router>
        <div className="App">
          <div className="App-header">
            <ul className="App-nav">
              <li><Link to="/">Home</Link></li>
              <li><Link to="/about">About</Link></li>
              <li><Link to="/another-page">Another Page</Link></li>
            </ul>
          </div>
          <Route exact path="/" component={Home} />
          <ScrollToTopRoute path="/about" component={About} />
          <ScrollToTopRoute path="/another-page" component={AnotherPage} />
        </div>
      </Router>
    );
  }
}

export default App;

从上面的代码中,有趣的是,只有在导航到/关于或/另一个页面时,才会执行滚动到顶部的操作。然而,当进行/没有滚动恢复将发生。

整个代码库可以在这里找到:https://github.com/rizedr/react-router-scroll-top

值得注意的是onUpdate={() =>窗口。scrollTo(0,0)}方法过时。

下面是react-router 4+的一个简单解决方案。

const history = createBrowserHistory()

history.listen(_ => {
    window.scrollTo(0, 0)  
})

<Router history={history}>

这是另一种方法。

对于react-router v4,您还可以以以下方式将侦听器绑定到历史事件中的change:

let firstMount = true;
const App = (props) => {
    if (typeof window != 'undefined') { //incase you have server-side rendering too             
        firstMount && props.history.listen((location, action) => {
            setImmediate(() => window.scrollTo(0, 0)); // ive explained why i used setImmediate below
        });
        firstMount = false;
    }

    return (
        <div>
            <MyHeader/>            
            <Switch>                            
                <Route path='/' exact={true} component={IndexPage} />
                <Route path='/other' component={OtherPage} />
                // ...
             </Switch>                        
            <MyFooter/>
        </div>
    );
}

//mounting app:
render((<BrowserRouter><Route component={App} /></BrowserRouter>), document.getElementById('root'));

如果点击链接改变了路由,那么没有setimmediation(),滚动级别也会被设置为0,但是如果用户在浏览器上按下后退按钮,那么它将不起作用,因为浏览器在按下后退按钮时手动将滚动级别重置到上一个级别,所以通过使用setimmediation(),我们使我们的函数在浏览器完成重置滚动级别后执行,从而给我们提供了预期的效果。

对于'REACT-ROUTER-DOM v6及以上'

我通过创建一个包装器函数并将其包装在所有路由上解决了以下问题。

请遵循以下步骤:

1:需要导入以下内容:

import {Routes, Route, BrowserRouter as Router, useLocation} from 'react-router-dom';
import {useLayoutEffect} from 'react';

2:在"App"函数上面写一个包装器函数:

const Wrapper = ({children}) => {
  const location = useLocation();
  useLayoutEffect(() => {
    document.documentElement.scrollTo(0, 0);
  }, [location.pathname]);
  return children
} 

3:现在在包装器函数中包装你的路由:

<BrowserRouter>
  <Wrapper>
    <Navbar />
      <Routes>
        <Route exact path="/" element={<Home/>} />
        <Route path="/Products" element={<Products/>} />
        <Route path="/Login" element={<Login/>} />
        <Route path="/Aggressive" element={<Aggressive/>} />
        <Route path="/Attendance" element={<Attendance/>} />
        <Route path="/Choking" element={<Choking/>} />
        <Route path="/EmptyCounter" element={<EmptyCounter/>} />
        <Route path="/FaceMask" element={<FaceMask/>} />
        <Route path="/Fainting" element={<Fainting/>} />
        <Route path="/Smoking" element={<Smoking/>} />
        <Route path="/SocialDistancing" element={<SocialDistancing/>} />
        <Route path="/Weapon" element={<Weapon/>} />
      </Routes>
    <Footer />
  </Wrapper>
</BrowserRouter>

这应该能解决问题。