导航到另一个页面时出现问题,其位置将保持与以前的页面相同。所以它不会自动滚动到顶部。我也尝试window.scrollTo(0, 0)
在onChange路由器上使用。我还使用了scrollBehavior来解决此问题,但没有成功。有什么建议吗?
document.body.scrollTop = 0;
在componentDidMount
你移动到组件
导航到另一个页面时出现问题,其位置将保持与以前的页面相同。所以它不会自动滚动到顶部。我也尝试window.scrollTo(0, 0)
在onChange路由器上使用。我还使用了scrollBehavior来解决此问题,但没有成功。有什么建议吗?
document.body.scrollTop = 0;
在componentDidMount
你移动到组件
Answers:
React Router v4的文档包含用于滚动还原的代码示例。这是他们的第一个代码示例,当页面导航到以下位置时,可作为“滚动到顶部”的站点范围解决方案:
class ScrollToTop extends Component {
componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) {
window.scrollTo(0, 0)
}
}
render() {
return this.props.children
}
}
export default withRouter(ScrollToTop)
然后将其呈现在您应用的顶部,但在路由器下方:
const App = () => (
<Router>
<ScrollToTop>
<App/>
</ScrollToTop>
</Router>
)
// or just render it bare anywhere you want, but just one :)
<ScrollToTop/>
显然,这适用于大多数情况,但是还有更多关于如何处理选项卡式接口以及为何尚未实现通用解决方案的信息。
Because browsers are starting to handle the “default case” and apps have varying scrolling needs (like this website!), we don’t ship with default scroll management. This guide should help you implement whatever scrolling needs you have.
让我很伤心,因为它们提供代码示例的所有选项实际上都可以通过属性设置包含在控件中,并且可以更改一些默认行为。恕我直言,这感觉超级骇人且未完成。意味着只有高级React开发人员才能正确进行路由,而没有#pitOfSuccess
work-arounds
此处都忽略的重要可访问性问题。@danielnixon +100
但上课是如此2018
ScrollToTop.js
import { useEffect } from 'react';
import { withRouter } from 'react-router-dom';
function ScrollToTop({ history }) {
useEffect(() => {
const unlisten = history.listen(() => {
window.scrollTo(0, 0);
});
return () => {
unlisten();
}
}, []);
return (null);
}
export default withRouter(ScrollToTop);
用法:
<Router>
<Fragment>
<ScrollToTop />
<Switch>
<Route path="/" exact component={Home} />
</Switch>
</Fragment>
</Router>
ScrollToTop也可以实现为包装器组件:
ScrollToTop.js
import React, { useEffect, Fragment } from 'react';
import { withRouter } from 'react-router-dom';
function ScrollToTop({ history, children }) {
useEffect(() => {
const unlisten = history.listen(() => {
window.scrollTo(0, 0);
});
return () => {
unlisten();
}
}, []);
return <Fragment>{children}</Fragment>;
}
export default withRouter(ScrollToTop);
用法:
<Router>
<ScrollToTop>
<Switch>
<Route path="/" exact component={Home} />
</Switch>
</ScrollToTop>
</Router>
scrollToTop
到<Route>
。它似乎是非常常用的功能。
action !== 'POP'
。侦听器接受动作作为第二个arg
此答案用于旧代码,对于路由器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);
}
您可以添加一些标志,例如“ scrolled = false”,然后进行更新:
componentDidUpdate() {
if(this.scrolled === false){
window.scrollTo(0,0);
scrolled = true;
}
}
window.scrollTo(0,0);
onUpdate
钩在react-router v4中已弃用-只是要指出这一点
onUpdate
吗?
对于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
我们可以检查位置路径名何时更改并将其与path
prop 匹配,如果满意,则恢复窗口滚动。
这种方法的妙处在于,我们可以拥有恢复滚动的路由和不恢复滚动的路由。
这是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;
从上面的代码中,有意思的是,只有在导航到/about
或/another-page
滚动到顶部动作时才会执行。但是,继续操作时/
不会发生滚动还原。
整个代码库可以在这里找到:https : //github.com/rizedr/react-router-scroll-top
Home
。现在滚动到的底部,Home
然后转到“ AnotherPage”,然后不滚动。现在,如果您再次访问Home
,则该页面将滚动到顶部。但是根据您的回答,home
页面应保持滚动状态。
值得注意的是该onUpdate={() => window.scrollTo(0, 0)}
方法已经过时。
这是适用于react-router 4+的简单解决方案。
const history = createBrowserHistory()
history.listen(_ => {
window.scrollTo(0, 0)
})
<Router history={history}>
#
并添加?
到我们的网址末尾时,您会遇到问题。在第一种情况下,您不应该滚动到顶部,在第二种情况下,您根本不应该滚动
如果您运行的是React 16.8+,则可以使用一个组件轻松处理,该组件将在每次导航时向上滚动窗口:
这在scrollToTop.js组件中
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
export default function ScrollToTop() {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
}
然后将其呈现在您应用的顶部,但在Router下方
。app.js中
import ScrollToTop from "./scrollToTop";
function App() {
return (
<Router>
<ScrollToTop />
<App />
</Router>
);
}
或在index.js中
import ScrollToTop from "./scrollToTop";
ReactDOM.render(
<BrowserRouter>
<ScrollToTop />
<App />
</BrowserRouter>
document.getElementById("root")
);
我的应用程序也遇到了同样的问题。使用下面的代码段可以帮助我单击下一步按钮滚动到页面顶部。
<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>
我想与正在使用的人分享我的解决方案,react-router-dom v5
因为这些v4解决方案都没有为我完成工作。
解决我的问题的是安装react-router-scroll-top并将包装器放入<App />
如下所示:
const App = () => (
<Router>
<ScrollToTop>
<App/>
</ScrollToTop>
</Router>
)
就是这样!有效!
挂钩是可组合的,并且自从React Router v5.1起,我们有了一个useHistory()
挂钩。因此,基于@zurfyx的答案,我为此功能创建了可重复使用的钩子:
// useScrollTop.ts
import { useHistory } from 'react-router-dom';
import { useEffect } from 'react';
/*
* Registers a history listener on mount which
* scrolls to the top of the page on route change
*/
export const useScrollTop = () => {
const history = useHistory();
useEffect(() => {
const unlisten = history.listen(() => {
window.scrollTo(0, 0);
});
return unlisten;
}, [history]);
};
您可以将React Hook添加到Route组件。使用useLayoutEffect
而不是自定义监听器。
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
可能对您更好。
React钩子2020 :)
import React, { useLayoutEffect } from 'react';
import { useLocation } from 'react-router-dom';
const ScrollToTop: React.FC = () => {
const { pathname } = useLocation();
useLayoutEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
};
export default ScrollToTop;
const ScrollToTop: React.FC = () => {
我不明白这ScrollToTop: React.FC
是什么意思
我编写了一个名为的高阶组件withScrollToTop
。此HOC带有两个标志:
onComponentWillMount
-是否在导航时滚动到顶部(componentWillMount
)onComponentDidUpdate
-是否在更新时滚动到顶部(componentDidUpdate
)。在未卸载组件但发生导航事件(例如,从/users/1
to)的情况下,此标志是必需的/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 v4,您还可以按以下方式绑定侦听器以更改历史事件:
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'));
setImmediate()
如果通过单击链接更改了路线,则滚动级别也不会设置为0,但是如果用户按下浏览器上的“后退”按钮,则它将不起作用,因为当按下“后退”按钮时,浏览器会手动将滚动级别重置为上一级,因此通过使用setImmediate()
我们,我们的功能将在浏览器完成重置滚动级别后执行,从而达到预期的效果。
使用React Router dom v4可以使用
创建一个scrollToTopComponent组件,如下所示
class ScrollToTop extends Component {
componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) {
window.scrollTo(0, 0)
}
}
render() {
return this.props.children
}
}
export default withRouter(ScrollToTop)
或者,如果您使用的是标签页,请使用下面的选项卡
class ScrollToTopOnMount extends Component {
componentDidMount() {
window.scrollTo(0, 0)
}
render() {
return null
}
}
class LongContent extends Component {
render() {
<div>
<ScrollToTopOnMount/>
<h1>Here is my long content page</h1>
</div>
}
}
// somewhere else
<Route path="/long-content" component={LongContent}/>
希望这有助于为更多的滚动恢复VIST有文档野兔反应路由器DOM滚动恢复
我发现这ReactDOM.findDomNode(this).scrollIntoView()
可行。我把它放在里面componentDidMount()
。
在您的中router.js
,只需在router
对象中添加此功能。这样就可以了。
scrollBehavior() {
document.getElementById('app').scrollIntoView();
},
像这样,
**Routes.js**
import vue from 'blah!'
import Router from 'blah!'
let router = new Router({
mode: 'history',
base: process.env.BASE_URL,
scrollBehavior() {
document.getElementById('app').scrollIntoView();
},
routes: [
{ url: "Solar System" },
{ url: "Milky Way" },
{ url: "Galaxy" },
]
});
这很hacky(但可以):我只是添加
window.scrollTo(0,0);
渲染();
componentDidMount
在新路线的组件中加入逻辑?