上拉加载数据
要实现上拉加载数据功能,首先想到需要调接口;其次需要判断在何时调接口;另外,对于这种上拉加载新数据的效果,一般接口是不固定的,最后的页码会根据下拉情况实时变化,以此来获取更多数据,并且获取更多数据的同时还要保证原来数据的有效性,不能移除原来数据;还有一点,拉取接口的时候,要保证上一次接口调用已经完成,才能再去拉下一次接口,否则得到的数据会发生错乱。最后需要判断何时已拉取到了所有的数据,不再进行接口调用了。
总结起来就是以下几点:
1.调用接口;
2.判断在何时拉取新接口;
3.将拉取的新数据与原数据拼接在一起;
4.接口拉取时机,保证上一次接口调用结束之后再进行下一次接口调用;
5.接口调用结束条件。
例子:本次要实现的是上拉加载新数据,接口是以https://huodong.com/couponlist/ + page的形式,其中,page是一个变化的值,根据每次下拉的动作来决定。页面首次渲染时,page值为1,当触发第一次下拉动作,并到达判断条件时,page加1,当前接口成为一个新接口,来获取新数据,一个page对应的接口下有10条数据,数据不足十条则代表已到所有数据的结尾了。
1.首先我需要把单个接口写好:
fetchJsonp(url).then(function(response){return response.json();}).then(res=>{.......}).catch(err=>{......})
2.然后我再在上面接口中根据实际要求,添加我所需要进行操作的代码,填充接口:
constructor(props){
super(props);
this.state={
data : ' ' , //定义一个接收接口数据的变量
res_len: 0 // 接口数据长度
}
this.handlefetch = this.handlefetch.bind(this);
this.getCouponList = this.getCouponList.bind(this);
this.fetch = false; //定义一个全局变量,监测本次接口是否调用完毕
this.page = 1; //控制接口中页码page的变化,更新接口
}
componentDidMount(){
const that = this;
that.getCouponList();
}
getCouponList(){
const that = this;
that.handlefetch(); // 第一次调用接口
window.οnscrοll=()=>{ //监听页面的滚动,判断是否到达再一次调接口的条件
//上卷距离
let st = document.documentElement.scrollTop||document.body.scrollTop;
//窗口可视区高度
let wh = document.documentElement.clientHeight;
// 文档总高度
let dh = document.documentElement.offsetHeight;
//判断滑动到了底部
if(st+wh+100>=dh){
//判断是否还需调用接口
if (that.state.res_len >= 10) {
that.handlefetch(); // 调用接口
}
}
}
}
handlefetch(){
const that = this;
if (!that.fetch) { //当fetch为flase时,说明当前没有接口调用,可进行接口调用
that.fetch = true; //开始进行接口调用时,将fetch置换为true,代表当前操作进行中
let url = 'https://huodong.com/couponlist/' + that.page;
that.page = that.page + 1; //每次调用接口时给page+1
fetchJsonp(url) .then(function(response){
response.json()
}).then(res=>{
const {msg , result , status} = res ; //拿到接口数据
that.setState(state=>({
data:state.data.concat(...result), //给变量赋值,将新数据拼接到原来数据中,保证原来 数据的有效性
res_len: result.length
}) ,function(){ ...... } //回调函数
)
that.fetch = false; //将fetch置为false,代表此次接口调用已经结束
}).catch(err=>{
......
})
}
说明:
1.如果要拿到这些数据data去做一些操作,由于setstate的异步性,无法知道data变量是否已经被赋予新值,所以如果要保证data有新值的情况下再进行操作,需要将这一些列操作函数写在setState方法的回调函数中,这样就能保证在setState执行完了后再操作回调函数。所以,操作函数就写到回调中。
2.何时滑动到了页面的底部区域(这个区域是自己定义的,如,距离底部100px范围内的整个区域),上卷距离+窗口可视区高度=文档总高度时,代表滑动到了最底部,但通常,我们需要在距离底部还有一段距离的时候,就开始触发接口调用,因此判断时需要加上一小段px,为判断条件。
3.判断是否到达底部,st+wh+100>=dh,此处不能写==,因为经过那一个临界条件时,无法精确到1px,不一定会触发接口,所以需要写成一个区域的形式,即>=,那么问题来了,有人会问了,只要我在这个区域内滑动,不就会连续拉取很多次接口了?所以,我们需要控制接口的拉取时机,不能在一个时间内重复多次调用接口,要保证上一次接口已经拉取完毕了,再进行下一次拉取。所以,需要用一个变量来监控当前接口是否调用完成。
4.是否还需要进行下一次拉取接口操作。本例中,每一个page对应的接口中有10条数据,如果数据不够10条,则说明可能还有数据,还需要进行接口调用,如果当前获取的数据数小于10条,则说明,数据已经全部拉取完毕,用that.state.res_len >= 10来判断。