To use:
import ScrollView from 'ScrollView.jsx`;
...
render() {
return (
<ScrollView>
{aListThatScrolls}
</ScrollView>
);
}
import React from 'react'; | |
import Styles from './ScrollView.less'; | |
export default React.createClass({ | |
getInitialState() { | |
return { | |
height: 0, | |
handlerScrollTop: 0, | |
handlerHide: true | |
}; | |
}, | |
handlerHider: null, | |
scrollHandler: null, | |
lastPos: 0, | |
componentDidMount() { | |
window.addEventListener('resize', this.handleResize); | |
document.addEventListener('mousemove', this.handleHandlerMouseMove); | |
document.addEventListener('mouseup', this.handleHandlerMouseUp); | |
this.updateHeight(); | |
}, | |
componentWillUnmount() { | |
window.removeEventListener('resize', this.removeResize); | |
document.removeEventListener('mousemove', this.handleHandlerMouseMove); | |
document.removeEventListener('mouseup', this.handleHandlerMouseUp); | |
}, | |
render() { | |
return ( | |
<div className="ScrollView"> | |
<div className="scrollbar"> | |
<div className={"handler " + (this.state.handlerHide ? 'hide' : '')} | |
style={{height: '20%', top: this.state.handlerScrollTop.toString() + '%'}} | |
onMouseDown={this.handleHandlerMouseDown}/> | |
</div> | |
<div className="scroller" onScroll={this.handleScroll} ref="scroller"> | |
{this.props.children} | |
</div> | |
</div> | |
); | |
}, | |
handleScroll(e) { | |
clearTimeout(this.handlerHider); | |
let pos = e.target.scrollTop / (e.target.scrollHeight- this.state.height) * 0.8; | |
this.setState({ | |
handlerScrollTop: pos * 100, | |
handlerHide: false | |
}, () => { | |
this.handlerHider = setTimeout(() => { | |
this.setState({handlerHide: true}); | |
}, 1500); | |
}); | |
if (pos < 0.2 && pos < this.lastPos && this.props.onApproachingTop) { | |
this.props.onApproachingTop(); | |
} | |
if (pos > 0.6 && pos > this.lastPos && this.props.onApproachingBottom) { | |
this.props.onApproachingBottom(); | |
} | |
this.lastPos = pos; | |
}, | |
handleResize() { | |
this.updateHeight(); | |
}, | |
handleHandlerMouseDown(e) { | |
this.scrollHandler = e.target; | |
clearTimeout(this.handlerHider); | |
this.setState({handlerHide: false}); | |
}, | |
handleHandlerMouseMove(e) { | |
if (this.scrollHandler) { | |
let pos = (e.pageY) / this.state.height; | |
pos = (pos < 0 ? 0 : (pos > 0.8 ? 0.8 : pos)) * 100; | |
React.findDOMNode(this.refs.scroller).scrollTop = pos * React.findDOMNode(this.refs.scroller).scrollHeight / 100; | |
} | |
}, | |
handleHandlerMouseUp(e) { | |
this.scrollHandler = null; | |
clearTimeout(this.handlerHider); | |
this.handlerHider = setTimeout(() => { | |
this.setState({handlerHide: true}); | |
}, 1500); | |
}, | |
updateHeight() { | |
this.setState({height: React.findDOMNode(this).offsetHeight}); | |
} | |
}); |
@import (reference) "../Base/Base.less"; | |
.ScrollView { | |
overflow: hidden; | |
height: 100%; | |
position: relative; | |
.scrollbar { | |
position: absolute; | |
width: 8px; | |
top: 0; | |
right: 0; | |
height: 100%; | |
.handler { | |
background-color: rgba(0, 0, 0, 0.5); | |
position: absolute; | |
width: 6px; | |
left: 1px; | |
border-radius: 3px; | |
z-index: 1; | |
.transition(@time: 0.2s, @type: background-color); | |
&.hide { | |
background-color: rgba(0, 0, 0, 0); | |
} | |
&:hover { | |
background-color: rgba(0, 0, 0, 0.7); | |
} | |
&:active, | |
&:focus { | |
cursor: default; | |
} | |
} | |
} | |
.scroller { | |
overflow-y: auto; | |
height: 100%; | |
position: absolute; | |
top: 0; | |
left: 0; | |
bottom: 0; | |
right: -20px; | |
padding-right: 20px; | |
} | |
} |
非常好用。
我都已经打算自己写了才发现你的组件,初步使用下来就感觉很棒了。谢谢。
目前感觉滚动时有一点生涩感,我自己再改进一下。
已经节省了我很多时间,再次感谢。