分页逻辑如果需要在多个页面使用,每次都写重复的代码显然很繁琐,所以将其封装为一个对象,因为对象可以保存状态,所以当初始化 了一个对象之后每次只需调用该对象的一个getMoreData方法即可查询数据,不用多写任何逻辑,基于这个思想实现了分页对象。
一、问题引出:
当实现上述方法时,要解决以下问题:
1、构造方法:
- req对象(url、method、data)
- start和count参数
2、请求上锁:
为了防止服务器请求数据慢,所以给服务器上锁,环节服务器压力,只有当当前请求结束之后才能进行下一次的请求。
3、url的拼接:
请求的是get的拼接参数,所以当url中有?时需将&拼接上,当无?时将?start=拼接上。
4、数据的返回:
- 返回null,此时说明服务器出现异常、故障或请求正在上锁,调用方同时直接return即可。
- 统一数据格式,下文代码处有体现,返回四个参数。
二、paging对象代码:
import {
Http
} from "./http";
class Paging {
/*提供getMoreData的接口,外界只需要调用这个方法就可以无限次的获取更多数据
* 1、提供构造方法,将req对象传入,包括get/post方法、data、url等信息。
* 2、书写外部使用的getMoreData方法
* 1.需要加锁和解锁的过程,防止用户重复发请求,只有当该条数据返回之后才能进行
* 2.只有当还有更多数据时才会发送请求
* 3、获取真实数据:
* 1.确定好url,即将url拼接好,因为参数是?填上去的,但是如果前面已经有?则要使用&链接
* 2.发送http请求,获取数据
* 3.判断 1错误 2数据为空 返回的结果不同,错误会进入全局异常管理,空就返回对应数据结构的空值。
* 4。计算是否还有更多数据,有的话就让start+=count
* 5.将上面得到的数据与原数据拼接。
* 6.返回对应的数据
* */
req
count
start
moreDataFlag = true // 是否还有更多数据
locker = false
url = ''
accumulator = []
//构造方法
constructor(req, count = 10, start = 0) {
this.req = req
this.count = count
this.start = start
this.url = this.req.url
}
//获取更多数据:
async getMoreData() {
//上一次请求还没结束
if (this._isLock()) {
return null
}
//没有更多数据了
if (!this.moreDataFlag) {
return null
}
const data = await this._getActualData()
//请求结束,释放锁
this._releaseLock()
return data
}
async _getActualData() {
//1、确定好url
const req = this._deaReqlUrl()
//2、发送请求
const paging = await Http.request(req)
if (!paging) {
//服务器端出现了异常
return null
}
//服务器没有数据了
if (paging.total === 0) {
return {
empty: true,
items: [],
moreData: false,
accumulator: []
}
}
//计算是否还有更多数据
this.moreDataFlag = this._accumulateMoreDataFlag(paging.total_page, paging.page)
//存在更多数据就要更新索引
if (this.moreDataFlag) {
this.start += this.count
}
//得到返回的数据
this._getAccumulator(paging.items)
return {
empty: false, //是否为空
items: paging.items, //当前请求得到的数据
moreData: this.moreDataFlag, // 是否还有更多数据
accumulator: this.accumulator //之前数据+刚刚得到的数据
}
}
//将新老数据拼接在一起
_getAccumulator(items) {
//concat函数必须要接收,不是引用类型的追加
this.accumulator = this.accumulator.concat(items)
}
//计算是否还有更多数据
_accumulateMoreDataFlag(total_page, page) {
return page < total_page - 1 //页码从0开始
}
//处理url问题
/**
* 因为接收到的req内url需要将start和count拼接上去,所以这步就是处理url问题
* */
_deaReqlUrl() {
let url = this.url
const param = `start=${this.start}&count=${this.count}`
//传来的req中的url类似与'/v1/spu?id=2'或'/v1/spu'
if (url.includes('?')) {
url += '&' + param
} else {
url += "?" + param
}
this.req.url = url
return this.req
}
//加锁 默认是false
_isLock() {
if (!this.locker) {
this.locker = true
return false
}
return true //上锁了
}
//释放锁
_releaseLock() {
this.locker = false
}
}
export {
Paging
}
上面引用的http类:
import {config} from "../config/config";
import {promisic} from "./util";
//传来的url格式类似 latst/spu
class Http {
static async request({url, data, method = 'GET'}) {
const res = await promisic(wx.request)({
url: `http:localhost:8080/v1/${url}`,
method,
data,
})
return res.data
}
}
export {
Http
}
调用方代码:
async initBottom() {
//创建分页对象
const paging = new Paging({
url: "spu/latest",
method: 'GET'
}, 5, 0)
//分页加载更多也需要,所以将对象保存起来
this.paging = paging
//获取数据
const data = await paging.getMoreData();
//出现异常或上锁时等情况
if (!data) {
return
}
},