saven
Version:
164 lines (161 loc) • 4.06 kB
JavaScript
import Nerv from 'nervjs'
import omit from 'omit.js'
import classNames from 'classnames'
import './style/index.scss'
function easeOutScroll (from, to, callback) {
if (from === to || typeof from !== 'number') {
return
}
let change = to - from
const dur = 500
const sTime = +new Date()
function linear (t, b, c, d) {
return c * t / d + b
}
function step () {
from = linear(+new Date() - sTime, from, change, dur)
if (from >= to) {
callback(to, true)
return
}
callback(from, false)
requestAnimationFrame(step)
}
step()
}
function throttle (fn, delay) {
let timer = null
return function () {
clearTimeout(timer)
timer = setTimeout(function () {
fn()
}, delay)
}
}
class ScrollView extends Nerv.Component {
constructor () {
super(...arguments)
}
componentDidMount () {
setTimeout(() => {
const props = this.props
if (props.scrollY && props.scrollTop) {
if ('scrollWithAnimation' in props) {
easeOutScroll(0, props.scrollTop, pos => {
this.container.scrollTop = pos
})
} else {
this.container.scrollTop = props.scrollTop
}
}
if (props.scrollX && props.scrollLeft) {
if ('scrollWithAnimation' in props) {
easeOutScroll(0, props.scrollLeft, pos => {
this.container.scrollLeft = pos
})
} else {
this.container.scrollLeft = props.scrollLeft
}
}
}, 10)
}
componentWillReceiveProps (nextProps) {
setTimeout(() => {
const props = nextProps
if (props.scrollY && props.scrollTop && this.props.scrollTop !== props.scrollTop) {
if ('scrollWithAnimation' in props) {
easeOutScroll(0, props.scrollTop, pos => {
this.container.scrollTop = pos
})
} else {
this.container.scrollTop = props.scrollTop
}
}
if (props.scrollX && props.scrollLeft && this.props.scrollLeft !== props.scrollLeft) {
if ('scrollWithAnimation' in props) {
easeOutScroll(0, props.scrollLeft, pos => {
this.container.scrollLeft = pos
})
} else {
this.container.scrollLeft = props.scrollLeft
}
}
}, 10)
}
render () {
const {
className,
onScroll,
onScrollToUpper,
onScrollToLower,
scrollX,
scrollY,
upperThreshold = 0,
lowerThreshold = 0
} = this.props
const cls = classNames(
'taro-scroll',
{
[`taro-scroll-view__scroll-x`]: scrollX,
[`taro-scroll-view__scroll-y`]: scrollY
},
className
)
const uperAndLower = () => {
const {
offsetWidth,
offsetHeight,
scrollLeft,
scrollTop,
scrollHeight,
scrollWidth
} = this.container
if (
onScrollToLower &&
((this.props.scrollY &&
offsetHeight + scrollTop + lowerThreshold >= scrollHeight) ||
(this.props.scrollX &&
offsetWidth + scrollLeft + lowerThreshold >= scrollWidth))
) {
onScrollToLower()
}
if (
onScrollToUpper &&
((this.props.scrollY && scrollTop <= upperThreshold) ||
(this.props.scrollX && scrollLeft <= upperThreshold))
) {
onScrollToUpper()
}
}
const uperAndLowerThrottle = throttle(uperAndLower, 200)
const _onScroll = e => {
const {
scrollLeft,
scrollTop,
scrollHeight,
scrollWidth
} = this.container
e.detail = {
scrollLeft,
scrollTop,
scrollHeight,
scrollWidth
}
uperAndLowerThrottle()
onScroll && onScroll(e)
}
return (
<div
ref={container => {
this.container = container
}}
{...omit(this.props, ['className'])}
className={cls}
onScroll={_onScroll}
>
{this.props.children}
</div>
)
}
}
export default ScrollView