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


当前回答

我的解决方案:我在我的屏幕组件中使用的组件(我想要滚动到顶部)。

import { useLayoutEffect } from 'react';

const ScrollToTop = () => {
    useLayoutEffect(() => {
        window.scrollTo(0, 0);
    }, []);

    return null;
};

export default ScrollToTop;

这可以在返回时保留滚动位置。 使用useEffect()对我来说是有bug的,当返回文档时,文档会滚动到顶部,当已经滚动的文档中的路由被更改时,也会有闪烁的效果。

其他回答

这是另一种方法。

对于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钩子(如果你没有使用React类):

const oldPage = useRef(pathname)

useEffect(() => {
  if (pathname !== oldPage.current) {
    try {
      window.scroll({
        top: 0,
        left: 0,
        behavior: 'smooth'
      })
    } catch (error) {
      // for older browser
      window.scrollTo(0, 0)
    }
    oldPage.current = pathname
  }
}, [pathname])

对我来说,是窗户。scrollTo(0,0)和document.documentElement。scrollTo(0,0)没有在我的所有屏幕上工作(只在一个屏幕上工作)。

然后,我意识到我的屏幕的溢出(滚动是允许的)不在窗口(因为我们有一些静态点,所以我们把溢出:auto在其他div)。

为了实现这一点,我做了以下测试:

useEffect(() => {
  const unlisten = history.listen(() => {
    console.log(document.documentElement.scrollTop)
    console.log(window.scrollTop)
    window.scrollTo(0, 0);
  });
  return () => {
    unlisten();
  }
}, []);

在所有的对数中,我得到0。

所以,我寻找我有滚动的容器,并放置一个id:

<div id="SOME-ID">
    ...
</div>

在我的ScrollToTop组件中,我放入:

useEffect(() => {
  const unlisten = history.listen(() => {
    window.scrollTo(0, 0);
    document.getElementById("SOME-ID")?.scrollTo(0, 0)
  });
  return () => {
    unlisten();
  }
}, []);

现在,当我用history.push("/SOME-ROUTE")转到一条新路线时,我的屏幕会转到顶部

一个可以添加到Route组件的React Hook。使用uselayouteeffect而不是自定义监听器。

import React, { useLayoutEffect } from 'react';
import { Switch, Route, useLocation } from 'react-router-dom';

export default function Routes() {
  const location = useLocation();
  // Scroll to top if path changes
  useLayoutEffect(() => {
    window.scrollTo(0, 0);
  }, [location.pathname]);

  return (
      <Switch>
        <Route exact path="/">

        </Route>
      </Switch>
  );
}

更新:更新到使用useLayoutEffect而不是useEffect,以减少视觉上的干扰。大致可以理解为:

useEffect:渲染组件->油漆到屏幕->滚动到顶部(运行效果) useLayoutEffect:渲染组件->滚动到顶部(运行效果)->油漆到屏幕

取决于您是在加载数据(考虑旋转器)还是有页面转换动画,useEffect可能更适合您。

我的解决方案:我在我的屏幕组件中使用的组件(我想要滚动到顶部)。

import { useLayoutEffect } from 'react';

const ScrollToTop = () => {
    useLayoutEffect(() => {
        window.scrollTo(0, 0);
    }, []);

    return null;
};

export default ScrollToTop;

这可以在返回时保留滚动位置。 使用useEffect()对我来说是有bug的,当返回文档时,文档会滚动到顶部,当已经滚动的文档中的路由被更改时,也会有闪烁的效果。