我有个问题,我不知道怎么解决。
在我的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;
这里还有另一种方法,它允许你选择你希望窗口滚动位置重置到的安装组件,而不需要大量复制ComponentDidUpdate/ComponentDidMount。
下面的例子是用ScrollIntoView()包装Blog组件,这样当Blog组件被挂载时,如果路由改变了,那么HOC的ComponentDidUpdate将更新窗口滚动位置。
你可以很容易地将它包裹在整个应用程序中,这样在任何路由改变时,它都会触发一个窗口重置。
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方法示例代码,以及使用withRouter包装ScrollIntoView)。
容器/ ScrollIntoView.js
import { PureComponent, Fragment } from "react";
class ScrollIntoView extends PureComponent {
componentDidMount = () => window.scrollTo(0, 0);
render = () => this.props.children
}
export default ScrollIntoView;
组件/ Home.js
import React from "react";
import ScrollIntoView from "../containers/ScrollIntoView";
export default () => (
<ScrollIntoView>
<div className="container">
<p>
Sample Text
</p>
</div>
</ScrollIntoView>
);
以上答案目前对我来说都没用。事实证明,. scrollto并不像. scrollintoview那样广泛兼容。
在App.js中,我们在componentWillMount()中添加了
this.props.history.listen((location, action) => {
setTimeout(() => { document.getElementById('root').scrollIntoView({ behavior: "smooth" }) }, 777)
})
这是唯一适用于我们的解决方案。root是我们应用的ID。“平滑”行为并不适用于每个浏览器/设备。777的超时有点保守,但我们在每个页面上都加载了大量数据,所以通过测试,这是必要的。更短的237可能适用于大多数应用程序。
钩的解决方案:
创建一个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>
文档:https://reacttraining.com/react-router/web/guides/scroll-restoration