关于如何去制作一个上拉加载更多的组件
2017-07-10 本文已影响0人
cb12hx
实现一个上拉加载更多,要考虑一下几个问题
1.什么时候触发加载
2.什么时候不触发
3.具体怎么触发
根据以上的几条,可以设计这样一个组件
1.什么时候触发,即滚动到什么位置时开始触发,此处就需要一个阈值进行判断,我们叫它threshold,
2.什么时候不触发,也许大家说只要不达到阈值时就不触发,其实这样是有偏差的,为什么呢,首先,滚动时,假如它的阈值设为50,那么小于等于50时,就会触发,此时假如我们在0-50之间随意更改值,那么就会导致一直触发,这显然不是我们想要的,一般不触发可以这么来判断,是否在加载数据,是否已经加载完所有的数据,所以,我们需要两个属性去判断isFetching,hasMore
3.怎么去触发,此时我们需要一个去触发的action,这个action每次执行之后,都会把pageIndex加1
总结一下,这个组件,我们需要一下几个props
1.threshold;2.isFetching;3.hasMore;4.action
好了,有了以上几条,接下来实操部分,首先,我们怎么去算出怎么threshold
getBoundingClientRect
此处我是用的getBoundingClientRect,这个方法在area中也用到了,我们来看看它的一些有用的值,left,right,top,bottom,width,height
1.left指元素的左边距可视区域左边的距离
2.right指元素的右边距可视区域左边的距离
3.top指元素的顶部距可视区域顶部的距离
4.bottom指元素的底部距可视区域顶部的距离
盗个图,一目了然
image.png然后我们只要每次去计算当前列表的底部距离减去可视区域的高度小于我们的阈值时,即触发加载,其实,讲到这里,核心已经差不多了,接下来看代码吧
import React, { PureComponent } from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import styles from './main.scss'
export default class Infinity extends PureComponent {
state = {
screenHeight: 0
}
render() {
const { hasMore } = this.props
return (
<div>
{this.props.children}
<p className={styles.infinity}>{hasMore ? '加载中...' : '没有更多了'}</p>
</div>
)
}
componentDidMount() {
if (!this.props.children) {
console.error('You must add a child!')
return
} else if (Object.prototype.toString.call(this.props.children) == '[object Array]' && this.props.children.length > 0) {
console.error('Too many child')
return
}
this.setState({
screenHeight: window.innerHeight
})
window.addEventListener('scroll', this.scroll)
this.pagination()
}
componentWillUnmount() {
window.removeListener('scroll', this.scroll)
}
scroll = () => {
const { panel, threshold } = this.props
var rect = ReactDOM.findDOMNode(this).parentNode.getBoundingClientRect()
let value = rect.bottom - this.state.screenHeight
if (value < threshold) {
this.pagination()
}
}
pagination() {
const { action, count, total, isFetching, hasMore } = this.props
if (!isFetching && hasMore) {
console.log('加载中')
action()
}
}
}
Infinity.propTypes = {
action: PropTypes.func, // 具体加载下一页的事件
threshold: PropTypes.number, // 加载的阈值
isFetching: PropTypes.bool,
hasMore: PropTypes.bool
}
Infinity.defaultProps = {
action: () => {},
threshold: 100,
isFetching: false,
hasMore: true
}
reducer中的处理
state = Immutable.update(state, 'dataList', (dataList, payload) => dataList.concat(payload), action.payload)
if (action.payload.length < state.pageSize) {
state = Immutable.merge(state, { hasMore: false })
}
return Immutable.update(state, 'pageIndex', (pageIndex, step) => pageIndex + step, 1)