原理
主要基于scrollTop + addEventListen实现。
关于Element.scrollTop
,MDN 上有很好的解释:
Element.scrollTop 属性可以获取或设置一个元素的内容垂直滚动的像素数。一个元素的 scrollTop 值是这个元素的内容顶部到它的视口可见内容顶部的距离的度量。当一个元素的内容没有产生垂直方向的滚动条,那么它的 scrollTop 值为0。
当内容滚动时,Element.scrollTop
的值会发生改变。scrollTop会实时更新已滚动的距离,基于此,很容易就能将该功能实现出来。
实现效果
backToTop组件实现
代码
import React from 'react'
import styled from 'styled-components'
class BackToTop 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 BackToTop
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;
`
解释
当往下滑动的距离超过 100 像素时,设置state中的hasScrolled 为 True,点击按钮后,回到顶部。
使用
我的demo基于 React-router-dom,嵌套本组件后结构如下:
class Index extends React.Component {
render() {
return (
<BrowserRouter><BackToTop><Switch><Route exact path="/" component={SearchBox}/><Route exact path="/index" component={SearchBox}/><Route exact path="/search" component={SearchBox}/>
{/*详情页*/}<Route path="/detail/:type/:id" component={Detail}/>
{/*其它*/}<Route component={NotFound}/>Switch>BackToTop>BrowserRouter>
)
}
}