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


当前回答

我的申请也遇到了同样的问题。使用下面的代码片段可以帮助我在单击下一个按钮时滚动到页面顶部。

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

然而,在浏览器返回时,这个问题仍然存在。经过大量的尝试,我意识到这是因为浏览器窗口的历史对象,它有一个属性scrollRestoration被设置为auto。将此设置为手动解决了我的问题。

function scrollToTop() {
    window.scrollTo(0, 0)
    if ('scrollRestoration' in history) {
        history.scrollRestoration = 'manual';
    }
}

<Router onUpdate= {scrollToTop} history={browserHistory}>
....
</Router>

其他回答

我写了一个叫withScrollToTop的高阶组件。这个HOC有两个标志:

onComponentWillMount -导航时是否滚动到顶部(componentWillMount) onComponentDidUpdate—是否在更新时滚动到顶部(componentDidUpdate)。该标志在组件没有卸载但发生导航事件的情况下是必要的,例如,从/users/1到/users/2。


// @flow
import type { Location } from 'react-router-dom';
import type { ComponentType } from 'react';

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

type Props = {
  location: Location,
};

type Options = {
  onComponentWillMount?: boolean,
  onComponentDidUpdate?: boolean,
};

const defaultOptions: Options = {
  onComponentWillMount: true,
  onComponentDidUpdate: true,
};

function scrollToTop() {
  window.scrollTo(0, 0);
}

const withScrollToTop = (WrappedComponent: ComponentType, options: Options = defaultOptions) => {
  return class withScrollToTopComponent extends Component<Props> {
    props: Props;

    componentWillMount() {
      if (options.onComponentWillMount) {
        scrollToTop();
      }
    }

    componentDidUpdate(prevProps: Props) {
      if (options.onComponentDidUpdate &&
        this.props.location.pathname !== prevProps.location.pathname) {
        scrollToTop();
      }
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
};

export default (WrappedComponent: ComponentType, options?: Options) => {
  return withRouter(withScrollToTop(WrappedComponent, options));
};

使用它:

import withScrollToTop from './withScrollToTop';

function MyComponent() { ... }

export default withScrollToTop(MyComponent);

对于我的应用程序,当通过链接导航时,有能力向上滚动是很重要的。但在点击标签(也是链接)时,不要滚动任何东西也是很重要的。此外,我的应用程序有一个先进的布局,因此可滚动的容器可以根据当前页面的布局和链接的位置而不同。

下面是我的解决方案:

为react-router-dom添加onClick处理程序的Link引入RouterLink包装器。当链接被单击时,它会找到最近的滚动容器并向上滚动。可以通过指定preservesroll(这是原始Link的默认行为)来选择退出此行为。

希望这能有所帮助。

// Helper to find nearest scrolled parent of a given node
const getScrollParent = (node) => {
  if (!node) {
    return null;
  }

  if (node.scrollTop > 0) {
    return node;
  } else {
    return getScrollParent(node.parentNode);
  }
};

interface RouterLinkProps extends LinkProps {
  preserveScroll?: boolean;
}
export const RouterLink: React.FC<RouterLinkProps> = ({ preserveScroll = false, ...linkProps }) => {
  const handleClick = useCallback(
    (val) => {
      const targetEl = val?.target;
      if (!targetEl || preserveScroll) {
        return;
      }
      const scrolledContainer = getScrollParent(targetEl);
      if (scrolledContainer) {
        scrolledContainer.scrollTo({
          top: 0,
          left: 0,
          behavior: 'smooth',
        });
      }
    },
    [preserveScroll],
  );

  const extraProps = useMemo(() => {
    if (!preserveScroll) {
      return {
        onClick: handleClick,
      };
    }
    return {};
  }, [handleClick, preserveScroll]);

  return <Link {...linkProps} {...extraProps} />;
};

现在,我可以使用这个包装器并获得所需的行为和足够的控制来调整它。是这样的:

<RouterLink to="/some/path">我向上滚动的链路</RouterLink> .

我的申请也遇到了同样的问题。使用下面的代码片段可以帮助我在单击下一个按钮时滚动到页面顶部。

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

然而,在浏览器返回时,这个问题仍然存在。经过大量的尝试,我意识到这是因为浏览器窗口的历史对象,它有一个属性scrollRestoration被设置为auto。将此设置为手动解决了我的问题。

function scrollToTop() {
    window.scrollTo(0, 0)
    if ('scrollRestoration' in history) {
        history.scrollRestoration = 'manual';
    }
}

<Router onUpdate= {scrollToTop} history={browserHistory}>
....
</Router>

一个可以添加到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 React from 'react';
const file = () => { document.body.scrollTop = 0; return( <div></div> ) }