在React中写一个回到顶部组件(back to top)

前文说过,最近在写一个基于 React + WP-Rest 的独立主题,而本文所说的回到顶部组件即是它的一部分。
原理及演示
关于Element.scrollTop
,MDN 上有很好的解释:
Element.scrollTop 属性可以获取或设置一个元素的内容垂直滚动的像素数。
一个元素的 scrollTop 值是这个元素的内容顶部到它的视口可见内容顶部的距离的度量。当一个元素的内容没有产生垂直方向的滚动条,那么它的 scrollTop 值为0。
当内容滚动时,Element.scrollTop
的值会发生改变。根据scrollTop
的变化设置组件状态,React 会自动更新 DOM,从而实现按钮的显示与隐藏。
组件
1.代码
import React from 'react'
import styled from 'styled-components'
class ScrollToTopWrapper extends React.Component {
constructor(props){
super(props);
this.state = { hasScrolled: false }
this.onScroll = this.onScroll.bind(this);
}
componentDidMount() {
window.onscroll = this.onScroll;
}
onScroll = () => {
if (document.documentElement.scrollTop > 100 && !this.state.hasScrolled) {
this.setState({ hasScrolled: true })
} else if (document.documentElement.scrollTop < 100 && this.state.hasScrolled) {
this.setState({ hasScrolled: false })
}
}
scrollToTop = () => {
document.documentElement.scrollTop = 0
}
render() {
return (
<React.Fragment>
{this.state.hasScrolled && (
<ScrollToTopIconContainer onClick={this.scrollToTop}>
<div>^</div>
<Button>回到顶部</Button>
</ScrollToTopIconContainer>
)}
<ScrollingWrapperContainer>
{this.props.children}
</ScrollingWrapperContainer>
</React.Fragment>
)
}
}
export default ScrollToTopWrapper
const ScrollingWrapperContainer = styled.div`
`
const ScrollToTopIconContainer = styled.div`
position: fixed;
bottom: 20px;
left: calc(50% - 50px);
z-index: 2;
cursor: pointer;
opacity: 0.4;
text-align: center;
&:hover {
opacity: 1;
animation: wiggle 1s ease;
animation-iteration-count: 1;
}
@keyframes wiggle {
20% { transform: translateY(6px); }
40% { transform: translateY(-6px); }
60% { transform: translateY(4px); }
80% { transform: translateY(-2px); }
100% { transform: translateY(0); }
}
`
const Button = styled.div`
background: black;
color: white;
font-family: Teko;
font-size: 16px;
line-height: 32px;
border-radius: 15px;
width: 100px;
padding: 4px 2px 4px 2px;
`
2.解释
当往下滑动的距离超过 100 像素时,设置布尔状态 hasScrolled 为 True,点击按钮后,回到顶部。
使用
我的工程基于 React-router,嵌套本组件后结构如下:
<HashRouter history={hashHistory}>
<div className={classes.root}>
<AppBar position="sticky">
{……}
</AppBar>
<ScrollToTopWrapper>
<Switch>
<Route exact path="/" component={……}></Route>
{……}
</Switch>
</ScrollToTopWrapper>
</div>
</HashRouter>
具体使用效果见演示站:http://www.acgame.fun