react+dva实现页面上滑加载数据功能
场景: 原PC页面分页展示的数据,现在为了用户使用方便,支持手机端就能随时查看;也就是说把本来PC展示的内容按照移动端的要求移植到手机上。于是老后端为了提高开发效率、节约开发成本,直接把原PC端分页接口甩在了我的脸上(这种情况基本上会经常碰到)。很多情况下前后端
要做的功能是可以互相甩的,就看谁理由逼格高、语气态度硬。当然我是那种热爱和平的人,如果别人嗯嗯啊啊推辞不愿做而自己又能做的事就不会去争的面红耳赤,毕竟代码敲的越多自身的收益也就越大,一味的甩锅和逃避就会失去很多提升自己的机会。
言归正传,本次的需求也很简单只要前端将分页展示的每页条数改成很大值,就可以拿到所有后台返回的数据了;但这样一来前端会出现一个问题,如果后台返回的数据量少三五十条还好,如果是三五百条或者更多,全部展示的时候手机就会出现明显的卡顿,针对这个问题前端可定要做类似PC那种分页效果:默认展示几条,在浏览完默认条数往下滑动的时候依次展示剩下内容即可。
实现思路: 进入页面,调用接口拿到全部数据,默认展示n条(本例中展示5条);在页面初次加载完毕后获取展示区域的DOM,给目标区域添加一个scroll滚动事件,每次触发滚动时把滚动的高度、目标区域高度之和与内容的scrollHeight进行比较;当前者等于后者时,表示内容已经滑动到了底部,此时将展示的数据源加上下一页的数据,重复此步骤直至展示全部数据。
步骤代码:
- 拿到数据,按分页的思路处理数据:
async componentDidMount(){
const {
dispatch } = this.props;
await dispatch({
type: 'dynamicLoading/fetchDataList',
payload: {
pageSize: 999999} // 本地mock数据模仿
});
const {
currentSize } = this.state; // 当前页面展示的条数,demo默认为5
const {
dynamicLoading } = this.props; // 所有数据
if(currentSize === 0) return;
// 数据源处理
let tempList = mapListHandleFunc(dynamicLoading.dataInfo, currentSize);
this.setState({
displayList: tempList, dataList: dynamicLoading.dataInfo});
const domNode = this.contentRef.current; // 获取DOM 并添加scroll事件
if(domNode){
domNode.addEventListener('scroll', this.onScrollFunc);
}
}
mapListHandleFunc方法将总数据按条件的进行截取:
function mapListHandleFunc(listData=[],size=0){
let tempList = [];
for(let i=0;i<listData.length;i++){
if(i>=size){
break;
}
tempList.push(listData[i]);
}
return tempList;
}
- 上滑判断数据加载(核心):
onScrollFunc=()=> {
const domNode = this.contentRef.current;
const clientHeight = domNode.clientHeight;
const scrollHeight = domNode.scrollHeight;
const scrollTop = domNode.scrollTop;
const {
currentSize, flag, dataList } = this.state;
if(scrollTop+clientHeight >= scrollHeight &a