在 react.js 中呈现后滚动到页面顶部
Scroll to the top of the page after render in react.js
我有一个问题,我不知道如何解决。
在我的 React 组件中,我在底部显示了一长串数据和几个链接。
单击任何此链接后,我用新的链接集合填充列表,需要滚动到顶部。
问题是 - 如何在呈现新集合后滚动到顶部?
'use strict';
// url of this component is #/:checklistId/:sectionId
var React = require('react'),
Router = require('react-router'),
sectionStore = require('./../stores/checklist-section-store');
function updateStateFromProps() {
var self = this;
sectionStore.getChecklistSectionContent({
checklistId: this.getParams().checklistId,
sectionId: this.getParams().sectionId
}).then(function (section) {
self.setState({
section,
componentReady: true
});
});
this.setState({componentReady: false});
}
var Checklist = React.createClass({
mixins: [Router.State],
componentWillMount: function () {
updateStateFromProps.call(this);
},
componentWillReceiveProps(){
updateStateFromProps.call(this);
},
render: function () {
if (this.state.componentReady) {
return(
<section className='checklist-section'>
<header className='section-header'>{ this.state.section.name } </header>
<Steps steps={ this.state.section.steps }/>
<a href=`#/${this.getParams().checklistId}/${this.state.section.nextSection.Id}`>
Next Section
</a>
</section>
);
} else {...}
}
});
module.exports = Checklist;
你可以使用这样的东西。 ReactDom 适用于 react.14。否则就做出反应。
componentDidUpdate = () => { ReactDom.findDOMNode(this).scrollIntoView(); }
2019 年 5 月 11 日针对 React 16+ 的更新
constructor(props) {
super(props)
this.childDiv = React.createRef()
}
componentDidMount = () => this.handleScroll()
componentDidUpdate = () => this.handleScroll()
handleScroll = () => {
const { index, selected } = this.props
if (index === selected) {
setTimeout(() => {
this.childDiv.current.scrollIntoView({ behavior: 'smooth' })
}, 500)
}
}
由于最初的解决方案是为 react 的早期版本提供的,这里有一个更新:
constructor(props) {
super(props)
this.myRef = React.createRef() // Create a ref object
}
componentDidMount() {
this.myRef.current.scrollTo(0, 0);
}
render() {
return <div ref={this.myRef}></div>
} // attach the ref property to a dom element
这可以而且可能应该使用 refs:
来处理
"... you can use ReactDOM.findDOMNode as an "escape hatch" but we don't recommend it since it breaks encapsulation and in almost every case there's a clearer way to structure your code within the React model."
示例代码:
class MyComponent extends React.Component {
componentDidMount() {
this._div.scrollTop = 0
}
render() {
return <div ref={(ref) => this._div = ref} />
}
}
最后..我用了:
componentDidMount() {
window.scrollTo(0, 0)
}
编辑:React v16.8+
useEffect(() => {
window.scrollTo(0, 0)
}, [])
你可以在路由器中这样做:
ReactDOM.render((
<Router onUpdate={() => window.scrollTo(0, 0)} history={browserHistory}>
<Route path='/' component={App}>
<IndexRoute component={Home}></IndexRoute>
<Route path="/about" component={About}/>
<Route path="/work">
<IndexRoute component={Work}></IndexRoute>
<Route path=":id" component={ProjectFull}></Route>
</Route>
<Route path="/blog" component={Blog}/>
</Route>
</Router>
), document.getElementById('root'));
onUpdate={() => window.scrollTo(0, 0)}
把滚动条置顶。
有关更多信息,请查看:codepen link
这是唯一对我有用的东西(使用 ES6 class 组件):
componentDidMount() {
ReactDOM.findDOMNode(this).scrollIntoView();
}
这是另一种方法,允许您选择要将 window 滚动位置重置到哪些安装的组件,而无需大量复制 ComponentDidUpdate/ComponentDidMount。
下面的示例是用 ScrollIntoView() 包装 Blog 组件,这样如果在安装 Blog 组件时路由发生变化,那么 HOC 的 ComponentDidUpdate 将更新 window 滚动位置。
您可以轻松地将它包裹在整个应用程序中,这样在任何路线更改时,它都会触发 window 重置。
ScrollIntoView.js
import React, { Component } from 'react';
import { withRouter } from 'react-router';
export default WrappedComponent => {
class ResetWindowScroll extends Component {
componentDidUpdate = (prevProps) => {
if(this.props.location !== prevProps.location) window.scrollTo(0,0);
}
render = () => <WrappedComponent {...this.props} />
}
return withRouter(ResetWindowScroll);
}
Routes.js
import React from 'react';
import { Route, IndexRoute } from 'react-router';
import App from '../components/App';
import About from '../components/pages/About';
import Blog from '../components/pages/Blog'
import Index from '../components/Landing';
import NotFound from '../components/navigation/NotFound';
import ScrollIntoView from '../components/navigation/ScrollIntoView';
export default (
<Route path="/" component={App}>
<IndexRoute component={Index} />
<Route path="/about" component={About} />
<Route path="/blog" component={ScrollIntoView(Blog)} />
<Route path="*" component={NotFound} />
</Route>
);
上面的示例效果很好,但是如果您已经迁移到 react-router-dom
,那么您可以通过创建一个包装组件的 HOC
来简化上面的示例。
再一次,您也可以轻松地将其包装在您的路线上(只需将 componentDidMount
方法更改为上面编写的 componentDidUpdate
方法示例代码,以及包装 ScrollIntoView
withRouter
).
containers/ScrollIntoView.js
import { PureComponent, Fragment } from "react";
class ScrollIntoView extends PureComponent {
componentDidMount = () => window.scrollTo(0, 0);
render = () => this.props.children
}
export default ScrollIntoView;
components/Home.js
import React from "react";
import ScrollIntoView from "../containers/ScrollIntoView";
export default () => (
<ScrollIntoView>
<div className="container">
<p>
Sample Text
</p>
</div>
</ScrollIntoView>
);
我正在使用 react-router ScrollToTop 组件,其代码在 react-router 文档中描述
https://reacttraining.com/react-router/web/guides/scroll-restoration/scroll-to-top
我正在更改单个路由文件中的代码,之后不需要更改每个组件中的代码。
示例代码 -
第 1 步 - 创建 ScrollToTop.js 组件
import React, { Component } from 'react';
import { withRouter } from 'react-router';
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)
第 2 步 - 在 App.js 文件中,在 <Router
之后添加 ScrollToTop 组件
const App = () => (
<Router>
<ScrollToTop>
<App/>
</ScrollToTop>
</Router>
)
以上所有对我都不起作用 - 不知道为什么但是:
componentDidMount(){
document.getElementById('HEADER').scrollIntoView();
}
有效,其中 HEADER 是我的 header 元素的 ID
在 React Routing 中存在一个问题,如果我们重定向到新路由,那么它不会自动将您带到页面顶部。
连我也遇到了同样的问题。
我刚刚将单行添加到我的组件中,它就像黄油一样工作。
componentDidMount() {
window.scrollTo(0, 0);
}
如果您在 移动设备 上这样做,至少在 chrome 上,您会在底部看到一个白色条。
当 URL 条消失时会发生这种情况。解决方案:
Change the css for height/min-height: 100% to height/min-height: 100vh.
此代码将在滚动上导致平滑行为:
<div onClick={() => {
ReactDOM.findDOMNode(this.headerRef)
.scrollIntoView({behavior: "smooth"});
}}
className='go-up-button' >
</div>
您可以在 scrollIntoView() 内部传递其他参数
可以使用以下语法:
element.scrollIntoView();
element.scrollIntoView(alignToTop); // Boolean parameter
element.scrollIntoView(scrollIntoViewOptions); // Object parameter
alignToTop 可选
是布尔值:
If true, the top of the element will be aligned to the top of the visible area of the scrollable ancestor. Corresponds to scrollIntoViewOptions: {block: "start", inline: "nearest"}. This is the default value.
If false, the bottom of the element will be aligned to the bottom of the visible area of the scrollable ancestor. Corresponds to scrollIntoViewOptions: {block: "end", inline: "nearest"}.
scrollIntoViewOptions 可选
是具有以下属性的对象:
*behavior* Optional
Defines the transition animation.
One of "auto", "instant", or "smooth". Defaults to "auto".
*block* Optional
One of "start", "center", "end", or "nearest". Defaults to "center".
*inline* Optional
One of "start", "center", "end", or "nearest". Defaults to "nearest".
可以在此处找到更多详细信息:MDN docs
像这样的东西在组件上对我有用:
<div ref="scroller" style={{height: 500, overflowX: "hidden", overflowY: "auto"}}>
//Content Here
</div>
然后在任何处理更新的函数中:
this.refs.scroller.scrollTop=0
所有解决方案都讨论了在 componentDidMount
或 componentDidUpdate
上添加滚动条,但使用 DOM。
我做了所有这些,但没有成功。
所以,想出了一些其他适合我的方法。
Added
componentDidUpdate() { window.scrollTo(0, 0) }
on the header, that mine is out of the <Switch></Switch>
element. Just free in the app. Works.
我也发现了一些ScrollRestoration的东西,但是我现在很懒。现在将保持“DidUpdate”方式。
以上答案中的 None 目前对我有效。事实证明 .scrollTo
没有 .scrollIntoView
.
广泛兼容
在我们的 App.js 中,在 componentWillMount()
中我们添加了
this.props.history.listen((location, action) => {
setTimeout(() => { document.getElementById('root').scrollIntoView({ behavior: "smooth" }) }, 777)
})
这是唯一对我们普遍适用的解决方案。
root
是我们App的ID。 "smooth" 行为并不适用于所有浏览器/设备。 777 超时有点保守,但是我们在每个页面加载大量数据,所以通过测试这是必要的。较短的 237 可能适用于大多数应用程序。
以上答案中的 None 目前对我有用。事实证明 .scrollTo
没有 .scrollIntoView
.
广泛兼容
在我们的 App.js 中,我们在 componentWillMount()
中添加了
this.props.history.listen((location, action) => {
setTimeout(() => { document.getElementById('root').scrollIntoView({ behavior: "smooth" }) }, 777)
})
这是唯一对我们普遍适用的解决方案。 root 是我们 App 的 ID。 "smooth" 行为并不适用于所有浏览器/设备。 777 超时有点保守,但是我们在每个页面加载大量数据,所以通过测试这是必要的。较短的 237 可能适用于大多数应用程序。
对于那些使用钩子的人,下面的代码将起作用。
React.useEffect(() => {
window.scrollTo(0, 0);
}, []);
注意,也可以直接导入useEffect:import { useEffect } from 'react'
我正在使用 React Hooks 并且想要一些可重复使用的东西,但也想要一些我可以随时调用的东西(而不是在渲染之后)。
// utils.js
export const useScrollToTop = (initialScrollState = false) => {
const [scrollToTop, setScrollToTop] = useState(initialScrollState);
useEffect(() => {
if (scrollToTop) {
setScrollToTop(false);
try {
window.scroll({
top: 0,
left: 0,
behavior: 'smooth',
});
} catch (error) {
window.scrollTo(0, 0);
}
}
}, [scrollToTop, setScrollToTop]);
return setScrollToTop;
};
然后使用钩子你可以这样做:
import { useScrollToTop } from 'utils';
const MyPage = (props) => {
// initialise useScrollToTop with true in order to scroll on page load
const setScrollToTop = useScrollToTop(true);
...
return <div onClick={() => setScrollToTop(true)}>click me to scroll to top</div>
}
Hook解决方案:
- 创建 ScrollToTop 挂钩
import { useEffect } from "react";
import { withRouter } from "react-router-dom";
const ScrollToTop = ({ children, location: { pathname } }) => {
useEffect(() => {
window.scrollTo({
top: 0,
left: 0,
behavior: "smooth"
});
}, [pathname]);
return children || null;
};
export default withRouter(ScrollToTop);
- 用它包装您的应用程序
<Router>
<ScrollToTop>
<App />
</ScrollToTop>
</Router>
Documentation : https://reacttraining.com/react-router/web/guides/scroll-restoration
在功能组件中使用 Hooks,
假设组件在结果 props
有更新时更新
import React, { useEffect } from 'react';
export const scrollTop = ({result}) => {
useEffect(() => {
window.scrollTo(0, 0);
}, [result])
}
我 运行 在这个问题中使用 Gatsby 构建了一个站点,其 Link 构建在 Reach Router 之上。这是必须进行的修改而不是默认行为,这似乎很奇怪。
无论如何,我尝试了上面的许多解决方案,唯一真正对我有用的是:
document.getElementById("WhateverIdYouWantToScrollTo").scrollIntoView()
我把它放在 useEffect 中,但你可以很容易地把它放在 componentDidMount 中,或者以你想要的任何其他方式触发它。
不确定为什么 window.scrollTo(0, 0) 对我(和其他人)不起作用。
如果我假设您正在渲染一个章节,例如每页一本书,您需要做的就是将其添加到您的代码中。这对我来说就像魔法一样有效。
componentDidUpdate(prevProps) {
if (prevProps.currentChapter !== this.props.currentChapter) {
window.scrollTo(0, 0);
}
}
有了这个,你就不需要在正在渲染的组件上创建一个 ref。
如果所有想做的都是简单的事情,这里有一个适合所有人的解决方案
添加这个迷你功能
scrollTop()
{
window.scrollTo({
top: 0,
behavior: "smooth"
});
}
从页脚调用如下函数
<a className="scroll-to-top rounded" style={{display: "inline"}} onClick={this.scrollTop}>TOP</a>
如果你想添加漂亮的样式这里是css
.scroll-to-top {
position: fixed;
right: 1rem;
bottom: 1rem;
display: none;
width: 2.75rem;
height: 2.75rem;
text-align: center;
color: #fff;
background: rgba(90, 92, 105, 0.5);
line-height: 46px;
}
这是我做的:
useEffect(() => ref.current.scrollTo(0, 0));
const ref = useRef()
return(
<div ref={ref}>
...
</div>
)
对我没有任何作用,但是:
componentDidMount(){
$( document ).ready(function() {
window.scrollTo(0,0);
});
}
这对我有用。
import React, { useEffect } from 'react';
useEffect(() => {
const body = document.querySelector('#root');
body.scrollIntoView({
behavior: 'smooth'
}, 500)
}, []);
对于功能组件;
import React, {useRef} from 'react';
function ScrollingExample (props) {
// create our ref
const refToTop = useRef();
return (
<h1 ref={refToTop}> I wanna be seen </h1>
// then add enough contents to show scroll on page
<a onClick={()=>{
setTimeout(() => { refToTop.current.scrollIntoView({ behavior: 'smooth' })}, 500)
}}> Take me to the element <a>
);
}
我尝试了所有方法,但这是唯一有效的方法。
useLayoutEffect(() => {
document.getElementById("someID").scrollTo(0, 0);
});
我在 index.html 页面上添加了一个事件侦听器,因为所有页面加载和重新加载都是通过它完成的。以下是片段。
// Event listener
addEventListener("load", function () {
setTimeout(hideURLbar, 0);
}, false);
function hideURLbar() {
window.scrollTo(0, 1);
}
点击后出现的页面,写入即可。
componentDidMount() {
window.scrollTo(0, 0);
}
有一段时间我也有同样的问题。添加 window.scrollTo(0, 0); 到每一页是痛苦和多余的。所以我添加了一个 HOC,它将包装我所有的路由,并将保留在 BrowserRouter 组件中:
<ScrollTop>
<Routes />
</ScrollTop>
在 ScrollTopComponent 内部,我们有以下内容:
import React, { useEffect } from "react";
import { useLocation } from "react-router-dom";
const ScrollTop = (props) => {
const { children } = props;
const location = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [location]);
return <main>{children}</main>;
};
export default ScrollTop;
看起来所有 useEffect 示例都没有考虑到您可能希望通过状态更改来触发它。
const [aStateVariable, setAStateVariable] = useState(false);
const handleClick = () => {
setAStateVariable(true);
}
useEffect(() => {
if(aStateVariable === true) {
window.scrollTo(0, 0)
}
}, [aStateVariable])
我在 React 17.0 中使用功能组件和 window.scroll、window.scrollTo 做一个 SPA,所有这些变体都不适合我。所以我使用 useRef 钩子做了一个解决方案。我使用 Ref 在组件顶部创建了一个 span 标签,然后使用 ref.current.scrollIntoView()
并产生效果
有一个简短的例子:
import React, { useEffect,useRef} from 'react';
export const ExampleComponent = () => {
const ref = useRef();
useEffect(() => {
ref.current.scrollIntoView()
}, []);
return(
<>
<span ref={ref}></span>
<YourCodeHere />
<MoreCode />
</>
)
}
功能组件的解决方案——使用useEffect() hook
useEffect(() => {
window.history.scrollRestoration = 'manual';}, []);
此解决方案适用于功能组件以及 Class 基础。
首先,我不喜欢在每次重新渲染时滚动到顶部的想法,相反,我喜欢特定事件的附件功能。
第 1 步:创建 ScrollToTop 函数
const scrollToTop = () => {
window.scrollTo({
top: 0,
behavior: "smooth",
});
};
第 2 步:在 event
例如 onClick
上调用此函数
onRowClick={scrollToTop()}
// onClick={scrollToTop()}
// etc...
我已经尝试过@sledgeweight 解决方案,但它对某些视图效果不佳。但是添加 setTimeout 似乎效果很好。以防有人遇到与我相同的问题。下面是我的代码。
import { useEffect } from 'react'
import { useLocation } from 'react-router-dom'
const ScrollToTop = () => {
const { pathname } = useLocation()
useEffect(() => {
console.log(pathname)
/* settimeout make sure this run after components have rendered. This will help fixing bug for some views where scroll to top not working perfectly */
setTimeout(() => {
window.scrollTo({ top: 0, behavior: 'smooth' })
}, 0)
}, [pathname])
return null
}
export default ScrollToTop
在AppRouter.js中使用它作为
<Router>
<ScrollToTop/>
<App>
</Router>
我有一个问题,我不知道如何解决。 在我的 React 组件中,我在底部显示了一长串数据和几个链接。 单击任何此链接后,我用新的链接集合填充列表,需要滚动到顶部。
问题是 - 如何在呈现新集合后滚动到顶部?
'use strict';
// url of this component is #/:checklistId/:sectionId
var React = require('react'),
Router = require('react-router'),
sectionStore = require('./../stores/checklist-section-store');
function updateStateFromProps() {
var self = this;
sectionStore.getChecklistSectionContent({
checklistId: this.getParams().checklistId,
sectionId: this.getParams().sectionId
}).then(function (section) {
self.setState({
section,
componentReady: true
});
});
this.setState({componentReady: false});
}
var Checklist = React.createClass({
mixins: [Router.State],
componentWillMount: function () {
updateStateFromProps.call(this);
},
componentWillReceiveProps(){
updateStateFromProps.call(this);
},
render: function () {
if (this.state.componentReady) {
return(
<section className='checklist-section'>
<header className='section-header'>{ this.state.section.name } </header>
<Steps steps={ this.state.section.steps }/>
<a href=`#/${this.getParams().checklistId}/${this.state.section.nextSection.Id}`>
Next Section
</a>
</section>
);
} else {...}
}
});
module.exports = Checklist;
你可以使用这样的东西。 ReactDom 适用于 react.14。否则就做出反应。
componentDidUpdate = () => { ReactDom.findDOMNode(this).scrollIntoView(); }
2019 年 5 月 11 日针对 React 16+ 的更新
constructor(props) {
super(props)
this.childDiv = React.createRef()
}
componentDidMount = () => this.handleScroll()
componentDidUpdate = () => this.handleScroll()
handleScroll = () => {
const { index, selected } = this.props
if (index === selected) {
setTimeout(() => {
this.childDiv.current.scrollIntoView({ behavior: 'smooth' })
}, 500)
}
}
由于最初的解决方案是为 react 的早期版本提供的,这里有一个更新:
constructor(props) {
super(props)
this.myRef = React.createRef() // Create a ref object
}
componentDidMount() {
this.myRef.current.scrollTo(0, 0);
}
render() {
return <div ref={this.myRef}></div>
} // attach the ref property to a dom element
这可以而且可能应该使用 refs:
来处理"... you can use ReactDOM.findDOMNode as an "escape hatch" but we don't recommend it since it breaks encapsulation and in almost every case there's a clearer way to structure your code within the React model."
示例代码:
class MyComponent extends React.Component {
componentDidMount() {
this._div.scrollTop = 0
}
render() {
return <div ref={(ref) => this._div = ref} />
}
}
最后..我用了:
componentDidMount() {
window.scrollTo(0, 0)
}
编辑:React v16.8+
useEffect(() => {
window.scrollTo(0, 0)
}, [])
你可以在路由器中这样做:
ReactDOM.render((
<Router onUpdate={() => window.scrollTo(0, 0)} history={browserHistory}>
<Route path='/' component={App}>
<IndexRoute component={Home}></IndexRoute>
<Route path="/about" component={About}/>
<Route path="/work">
<IndexRoute component={Work}></IndexRoute>
<Route path=":id" component={ProjectFull}></Route>
</Route>
<Route path="/blog" component={Blog}/>
</Route>
</Router>
), document.getElementById('root'));
onUpdate={() => window.scrollTo(0, 0)}
把滚动条置顶。
有关更多信息,请查看:codepen link
这是唯一对我有用的东西(使用 ES6 class 组件):
componentDidMount() {
ReactDOM.findDOMNode(this).scrollIntoView();
}
这是另一种方法,允许您选择要将 window 滚动位置重置到哪些安装的组件,而无需大量复制 ComponentDidUpdate/ComponentDidMount。
下面的示例是用 ScrollIntoView() 包装 Blog 组件,这样如果在安装 Blog 组件时路由发生变化,那么 HOC 的 ComponentDidUpdate 将更新 window 滚动位置。
您可以轻松地将它包裹在整个应用程序中,这样在任何路线更改时,它都会触发 window 重置。
ScrollIntoView.js
import React, { Component } from 'react';
import { withRouter } from 'react-router';
export default WrappedComponent => {
class ResetWindowScroll extends Component {
componentDidUpdate = (prevProps) => {
if(this.props.location !== prevProps.location) window.scrollTo(0,0);
}
render = () => <WrappedComponent {...this.props} />
}
return withRouter(ResetWindowScroll);
}
Routes.js
import React from 'react';
import { Route, IndexRoute } from 'react-router';
import App from '../components/App';
import About from '../components/pages/About';
import Blog from '../components/pages/Blog'
import Index from '../components/Landing';
import NotFound from '../components/navigation/NotFound';
import ScrollIntoView from '../components/navigation/ScrollIntoView';
export default (
<Route path="/" component={App}>
<IndexRoute component={Index} />
<Route path="/about" component={About} />
<Route path="/blog" component={ScrollIntoView(Blog)} />
<Route path="*" component={NotFound} />
</Route>
);
上面的示例效果很好,但是如果您已经迁移到 react-router-dom
,那么您可以通过创建一个包装组件的 HOC
来简化上面的示例。
再一次,您也可以轻松地将其包装在您的路线上(只需将 componentDidMount
方法更改为上面编写的 componentDidUpdate
方法示例代码,以及包装 ScrollIntoView
withRouter
).
containers/ScrollIntoView.js
import { PureComponent, Fragment } from "react";
class ScrollIntoView extends PureComponent {
componentDidMount = () => window.scrollTo(0, 0);
render = () => this.props.children
}
export default ScrollIntoView;
components/Home.js
import React from "react";
import ScrollIntoView from "../containers/ScrollIntoView";
export default () => (
<ScrollIntoView>
<div className="container">
<p>
Sample Text
</p>
</div>
</ScrollIntoView>
);
我正在使用 react-router ScrollToTop 组件,其代码在 react-router 文档中描述
https://reacttraining.com/react-router/web/guides/scroll-restoration/scroll-to-top
我正在更改单个路由文件中的代码,之后不需要更改每个组件中的代码。
示例代码 -
第 1 步 - 创建 ScrollToTop.js 组件
import React, { Component } from 'react';
import { withRouter } from 'react-router';
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)
第 2 步 - 在 App.js 文件中,在 <Router
const App = () => (
<Router>
<ScrollToTop>
<App/>
</ScrollToTop>
</Router>
)
以上所有对我都不起作用 - 不知道为什么但是:
componentDidMount(){
document.getElementById('HEADER').scrollIntoView();
}
有效,其中 HEADER 是我的 header 元素的 ID
在 React Routing 中存在一个问题,如果我们重定向到新路由,那么它不会自动将您带到页面顶部。
连我也遇到了同样的问题。
我刚刚将单行添加到我的组件中,它就像黄油一样工作。
componentDidMount() {
window.scrollTo(0, 0);
}
如果您在 移动设备 上这样做,至少在 chrome 上,您会在底部看到一个白色条。
当 URL 条消失时会发生这种情况。解决方案:
Change the css for height/min-height: 100% to height/min-height: 100vh.
此代码将在滚动上导致平滑行为:
<div onClick={() => {
ReactDOM.findDOMNode(this.headerRef)
.scrollIntoView({behavior: "smooth"});
}}
className='go-up-button' >
</div>
您可以在 scrollIntoView() 内部传递其他参数 可以使用以下语法:
element.scrollIntoView();
element.scrollIntoView(alignToTop); // Boolean parameter
element.scrollIntoView(scrollIntoViewOptions); // Object parameter
alignToTop 可选 是布尔值:
If true, the top of the element will be aligned to the top of the visible area of the scrollable ancestor. Corresponds to scrollIntoViewOptions: {block: "start", inline: "nearest"}. This is the default value.
If false, the bottom of the element will be aligned to the bottom of the visible area of the scrollable ancestor. Corresponds to scrollIntoViewOptions: {block: "end", inline: "nearest"}.
scrollIntoViewOptions 可选 是具有以下属性的对象:
*behavior* Optional
Defines the transition animation.
One of "auto", "instant", or "smooth". Defaults to "auto".
*block* Optional
One of "start", "center", "end", or "nearest". Defaults to "center".
*inline* Optional
One of "start", "center", "end", or "nearest". Defaults to "nearest".
可以在此处找到更多详细信息:MDN docs
像这样的东西在组件上对我有用:
<div ref="scroller" style={{height: 500, overflowX: "hidden", overflowY: "auto"}}>
//Content Here
</div>
然后在任何处理更新的函数中:
this.refs.scroller.scrollTop=0
所有解决方案都讨论了在 componentDidMount
或 componentDidUpdate
上添加滚动条,但使用 DOM。
我做了所有这些,但没有成功。
所以,想出了一些其他适合我的方法。
Added
componentDidUpdate() { window.scrollTo(0, 0) }
on the header, that mine is out of the<Switch></Switch>
element. Just free in the app. Works.
我也发现了一些ScrollRestoration的东西,但是我现在很懒。现在将保持“DidUpdate”方式。
None 目前对我有效。事实证明 .scrollTo
没有 .scrollIntoView
.
在我们的 App.js 中,在 componentWillMount()
中我们添加了
this.props.history.listen((location, action) => {
setTimeout(() => { document.getElementById('root').scrollIntoView({ behavior: "smooth" }) }, 777)
})
这是唯一对我们普遍适用的解决方案。
root
是我们App的ID。 "smooth" 行为并不适用于所有浏览器/设备。 777 超时有点保守,但是我们在每个页面加载大量数据,所以通过测试这是必要的。较短的 237 可能适用于大多数应用程序。
None 目前对我有用。事实证明 .scrollTo
没有 .scrollIntoView
.
在我们的 App.js 中,我们在 componentWillMount()
中添加了
this.props.history.listen((location, action) => {
setTimeout(() => { document.getElementById('root').scrollIntoView({ behavior: "smooth" }) }, 777)
})
这是唯一对我们普遍适用的解决方案。 root 是我们 App 的 ID。 "smooth" 行为并不适用于所有浏览器/设备。 777 超时有点保守,但是我们在每个页面加载大量数据,所以通过测试这是必要的。较短的 237 可能适用于大多数应用程序。
对于那些使用钩子的人,下面的代码将起作用。
React.useEffect(() => {
window.scrollTo(0, 0);
}, []);
注意,也可以直接导入useEffect:import { useEffect } from 'react'
我正在使用 React Hooks 并且想要一些可重复使用的东西,但也想要一些我可以随时调用的东西(而不是在渲染之后)。
// utils.js
export const useScrollToTop = (initialScrollState = false) => {
const [scrollToTop, setScrollToTop] = useState(initialScrollState);
useEffect(() => {
if (scrollToTop) {
setScrollToTop(false);
try {
window.scroll({
top: 0,
left: 0,
behavior: 'smooth',
});
} catch (error) {
window.scrollTo(0, 0);
}
}
}, [scrollToTop, setScrollToTop]);
return setScrollToTop;
};
然后使用钩子你可以这样做:
import { useScrollToTop } from 'utils';
const MyPage = (props) => {
// initialise useScrollToTop with true in order to scroll on page load
const setScrollToTop = useScrollToTop(true);
...
return <div onClick={() => setScrollToTop(true)}>click me to scroll to top</div>
}
Hook解决方案:
- 创建 ScrollToTop 挂钩
import { useEffect } from "react";
import { withRouter } from "react-router-dom";
const ScrollToTop = ({ children, location: { pathname } }) => {
useEffect(() => {
window.scrollTo({
top: 0,
left: 0,
behavior: "smooth"
});
}, [pathname]);
return children || null;
};
export default withRouter(ScrollToTop);
- 用它包装您的应用程序
<Router>
<ScrollToTop>
<App />
</ScrollToTop>
</Router>
Documentation : https://reacttraining.com/react-router/web/guides/scroll-restoration
在功能组件中使用 Hooks, 假设组件在结果 props
有更新时更新import React, { useEffect } from 'react';
export const scrollTop = ({result}) => {
useEffect(() => {
window.scrollTo(0, 0);
}, [result])
}
我 运行 在这个问题中使用 Gatsby 构建了一个站点,其 Link 构建在 Reach Router 之上。这是必须进行的修改而不是默认行为,这似乎很奇怪。
无论如何,我尝试了上面的许多解决方案,唯一真正对我有用的是:
document.getElementById("WhateverIdYouWantToScrollTo").scrollIntoView()
我把它放在 useEffect 中,但你可以很容易地把它放在 componentDidMount 中,或者以你想要的任何其他方式触发它。
不确定为什么 window.scrollTo(0, 0) 对我(和其他人)不起作用。
如果我假设您正在渲染一个章节,例如每页一本书,您需要做的就是将其添加到您的代码中。这对我来说就像魔法一样有效。
componentDidUpdate(prevProps) {
if (prevProps.currentChapter !== this.props.currentChapter) {
window.scrollTo(0, 0);
}
}
有了这个,你就不需要在正在渲染的组件上创建一个 ref。
如果所有想做的都是简单的事情,这里有一个适合所有人的解决方案
添加这个迷你功能
scrollTop()
{
window.scrollTo({
top: 0,
behavior: "smooth"
});
}
从页脚调用如下函数
<a className="scroll-to-top rounded" style={{display: "inline"}} onClick={this.scrollTop}>TOP</a>
如果你想添加漂亮的样式这里是css
.scroll-to-top {
position: fixed;
right: 1rem;
bottom: 1rem;
display: none;
width: 2.75rem;
height: 2.75rem;
text-align: center;
color: #fff;
background: rgba(90, 92, 105, 0.5);
line-height: 46px;
}
这是我做的:
useEffect(() => ref.current.scrollTo(0, 0));
const ref = useRef()
return(
<div ref={ref}>
...
</div>
)
对我没有任何作用,但是:
componentDidMount(){
$( document ).ready(function() {
window.scrollTo(0,0);
});
}
这对我有用。
import React, { useEffect } from 'react';
useEffect(() => {
const body = document.querySelector('#root');
body.scrollIntoView({
behavior: 'smooth'
}, 500)
}, []);
对于功能组件;
import React, {useRef} from 'react';
function ScrollingExample (props) {
// create our ref
const refToTop = useRef();
return (
<h1 ref={refToTop}> I wanna be seen </h1>
// then add enough contents to show scroll on page
<a onClick={()=>{
setTimeout(() => { refToTop.current.scrollIntoView({ behavior: 'smooth' })}, 500)
}}> Take me to the element <a>
);
}
我尝试了所有方法,但这是唯一有效的方法。
useLayoutEffect(() => {
document.getElementById("someID").scrollTo(0, 0);
});
我在 index.html 页面上添加了一个事件侦听器,因为所有页面加载和重新加载都是通过它完成的。以下是片段。
// Event listener
addEventListener("load", function () {
setTimeout(hideURLbar, 0);
}, false);
function hideURLbar() {
window.scrollTo(0, 1);
}
点击后出现的页面,写入即可。
componentDidMount() {
window.scrollTo(0, 0);
}
有一段时间我也有同样的问题。添加 window.scrollTo(0, 0); 到每一页是痛苦和多余的。所以我添加了一个 HOC,它将包装我所有的路由,并将保留在 BrowserRouter 组件中:
<ScrollTop>
<Routes />
</ScrollTop>
在 ScrollTopComponent 内部,我们有以下内容:
import React, { useEffect } from "react";
import { useLocation } from "react-router-dom";
const ScrollTop = (props) => {
const { children } = props;
const location = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [location]);
return <main>{children}</main>;
};
export default ScrollTop;
看起来所有 useEffect 示例都没有考虑到您可能希望通过状态更改来触发它。
const [aStateVariable, setAStateVariable] = useState(false);
const handleClick = () => {
setAStateVariable(true);
}
useEffect(() => {
if(aStateVariable === true) {
window.scrollTo(0, 0)
}
}, [aStateVariable])
我在 React 17.0 中使用功能组件和 window.scroll、window.scrollTo 做一个 SPA,所有这些变体都不适合我。所以我使用 useRef 钩子做了一个解决方案。我使用 Ref 在组件顶部创建了一个 span 标签,然后使用 ref.current.scrollIntoView()
并产生效果有一个简短的例子:
import React, { useEffect,useRef} from 'react';
export const ExampleComponent = () => {
const ref = useRef();
useEffect(() => {
ref.current.scrollIntoView()
}, []);
return(
<>
<span ref={ref}></span>
<YourCodeHere />
<MoreCode />
</>
) }
功能组件的解决方案——使用useEffect() hook
useEffect(() => {
window.history.scrollRestoration = 'manual';}, []);
此解决方案适用于功能组件以及 Class 基础。
首先,我不喜欢在每次重新渲染时滚动到顶部的想法,相反,我喜欢特定事件的附件功能。
第 1 步:创建 ScrollToTop 函数
const scrollToTop = () => {
window.scrollTo({
top: 0,
behavior: "smooth",
});
};
第 2 步:在 event
例如 onClick
上调用此函数
onRowClick={scrollToTop()}
// onClick={scrollToTop()}
// etc...
我已经尝试过@sledgeweight 解决方案,但它对某些视图效果不佳。但是添加 setTimeout 似乎效果很好。以防有人遇到与我相同的问题。下面是我的代码。
import { useEffect } from 'react'
import { useLocation } from 'react-router-dom'
const ScrollToTop = () => {
const { pathname } = useLocation()
useEffect(() => {
console.log(pathname)
/* settimeout make sure this run after components have rendered. This will help fixing bug for some views where scroll to top not working perfectly */
setTimeout(() => {
window.scrollTo({ top: 0, behavior: 'smooth' })
}, 0)
}, [pathname])
return null
}
export default ScrollToTop
在AppRouter.js中使用它作为
<Router>
<ScrollToTop/>
<App>
</Router>