小程序下滑分页获取数据封装

可能情况:

1、一条数据没有

2、到最后一页

3、请求状态: 正在加载、加载完成、没有更多数据

4、上滑触底,获取数据,应避免重复发送请求,所以使用数据锁

5、防抖和节流:还可以禁用、倒计时、模态等方式防止重复发送请求

思路:

1、判断是否还有数据

2、设置锁,锁开正常获取数据,锁关,证明还在请求数据,后面点击操作不做处理

3、设置一个属性,作为判断是否是最后一页的标识,

4、设置一个获取实时url的属性,因为每次请求的数据的页码都不一样,所以整个url都不一样,需要获取到最新的url

5、发送请求,返回结果为空,返回数据一个空对象,返回结果非空,判断是否是最后一页,并设置最后一页的属性值是true/false

6、如果还有数据,请求的起始条数加上每次获取的条数

7、数据累加

8、释放锁

/**
 * 分页类不关心细节
 * 当用户调用类,请求需要下一页的数据,直接返回数据
 * paging 需要保存状态,所以应该要以实例化的形式供调用方调用
 */
import {Http} from "./http";

class Paging {
    start
    count
    url   //最原始的url 即没有被覆盖的url
    locker = false
    req
    moreData = true   //是否有更多数据
    accumulator  //累加的数据,每次获取新数据要和原来的数据进行累加
    // 初始方法
    // req 传入的对象,这个对象有可能不止一个url  还带有其他的参数
    /**
     * 初始构造方法
     * @param req  传入的对象,这个对象有可能不止一个url  还带有其他的参数
     * @param count  每页条数
     * @param start  从第几条开始查
     */
    constructor(req, count, start = 0) {
        this.start = start
        this.count = count
        this.req = req
        this.url = req.url
    }

    /**
     * 业务调用主方法
     * @returns {Promise<{item: *[], moreData: boolean, accumulator: *[], empty: boolean}|{item: *, moreData: *, accumulator: *, empty: boolean}>}
     */
    async getMoreData() {
        // 检查锁的状态,如果锁是锁住的,证明还有别的请求还没返回,其他的请求将不会进行,当请求返回结果之后,应该释放锁

        //判断是否还有数据
        if (!this.moreData) {
            return
        }
        // 检查是否已经锁了,也就是请求的数据是否已经返回
        if (!this._getLocker()) {
            return
        }
        // 真实请求数据
        const data = await this._actualGetData()
        // 释放锁
        this._releaseLocker()
        return data
    }

    /**
     * 真实发送请求、判断数据结构(异常处理等情况),返回一个对象
     * @returns {Promise<null|{item: [], moreData: boolean, accumulator: [], empty: boolean}|{item: *, moreData: *, accumulator: *, empty: boolean}>}
     * @private
     */
    async _actualGetData() {
        const req = this._getCurrentReq()
        let paging = await Http.request(req)
        if (!paging) {
            return null
        }
        if (paging.total === 0) {
            return {
                empty: true,
                item: [],
                moreData: false, // 是否为最后一页的标识
                accumulator: []
            }
        }
        this.moreData = this._moreData(paging.total_page, paging.page)
        // 判断是否还有数据
        if (this.moreData) {
            this.start += this.count
        }
        this._accumulate(paging.items)
        return {
            empty: false,
            item: paging.items,
            moreData: this.moreData, // 是否为最后一页的标识
            accumulator: this.accumulator
        }
    }

    /**
     * 获取当前的对象,也就是当前返回的数据对象
     * @returns {*}
     * @private
     */
    _getCurrentReq() {
        let url = this.url
        const params = `start=${this.start}&count=${this.count}`
        if (url.indexOf('?') !== -1) {
            // 当访问的地址没有包含其他的参数,如 url= v1/spu/latest + '?' + params
            url += '&' + params
        } else {
            // 当访问的地址包含其他的参数,如 url= v1/spu/latest?other=abc + '&' + params
            url += '?' + params
        }
        this.req.url = url
        return this.req
    }

    /**
     * 判断是否是最后一页,是否还有数据
     * @param totalPage  总页数
     * @param pageNum  当前页数,0开始计数
     * @returns {boolean}
     * @private
     */
    _moreData(totalPage, pageNum) {
        return pageNum < totalPage - 1
    }

    /**
     * 累加每次请求的数据
     * @param items  请求返回的数据
     * @private
     */
    _accumulate(items) {
        this.accumulator = this.accumulator.concat(items)
    }

    /**
     * 获取锁的状态
     * @returns {boolean}
     * @private
     */
    _getLocker() {
        // 如果锁是锁住的
        if (this.locker) {
            return false
        }
        // 如果锁是开的
        this.locker = true
        return true
    }

    /**
     * 释放锁
     * @private
     */
    _releaseLocker() {
        this.locker = false
    }
}

export {Paging}