分页在项目中是很普遍存在的,如何封装才能让使用者使用方便,让代码可读性强,之前在写代码的过程中,很少注意这方面的东西,但是随着年龄的增大,作为程序员,面子肯定是要的,就像我想写的一手好字,同样,我也想写出优雅的代码!七月老师的风袖项目,这里的场景是小程序中的分页实现,里面那个分页的封装很值得学习,简单记录一下!
一、微信小程序中分页问题
微信小程序中分页需要考虑哪些方面呢?如何才能做好一个分页呢?以下这些方面存在的问题,你在做小程序中分页的时候考虑到了吗?反正我在做分页的时候是没有考虑这么全面的,没事,一直在学习的路上!
1、一条数据也没有,为空的情况
2、是否是最后一页,还有没有更多数据
3、请求分页数据的累加
这个不像PC端分页,有严格的分页按钮来点击,你点击哪页的数据,我来请求加载哪页的数据就行,小程序中的分页是用户触发上拉触底事件,来进行更多也就是下一页数据的加载的,这里就存在分页数据累加的问题,需要将已经请求的数据和请求的下一页数据进行累加,然后使用setData()方法进行重新渲染,显示出来,例如:总共有100条数据,第一次加载1-20,第二次加载21-40 显示1-40数据 ... 直到100数据加载完成,提示用户加载完成,没有更多数据
4、分页数据的加载状态
非分页数据 a 正在加载 b 空
分页数据 a 正在加载 b 加载完成 c 空
5、上滑触低,加载分页数据,避免用户重复发送过多请求,导致数据库查询次数过多,数据库崩溃
二、代码实现
将分页相关的方法封装成Paging类,调用使用方直接实例化Paging类。然后调用getMoreData()方法进行分页数据的请求
1、paging类整体结构搭建(毛坯房)
(1)封装类的时候首先明确需求,这里的具体就是想要获取到分页数据,那么Paging类中需要一个方法来实现这个需求
(2)getMoreData()方法 相当于Generator 生成器中的next方法
(3)参数如何处理 如何传递到Paging类中 这里用到的是constructor 构造器 初始化一些必要的参数
1 class Paging{ 2 start 3 count 4 url 5 6 constructor(url, count, start){ 7 this.count = count 8 this.start = start 9 this.url = url 10 } 11 getMoreData(){ 12 //生成器 generator 13 } 14 }
2、Paging类主方法简单封装(改水,改电,铺地板)
(1)看看最重要的getMoreData()方法,如何进行数据的获取 这里首先需要考虑的就是数据锁的问题,封装_getLocker()和_releaseLocker()方法
(2)尝试着将数据锁加到getMoreData方法中
(3)新建一个真正的获取数据的方法 _actualGetData()方法
1 class Paging{ 2 start 3 count 4 url 5 locker = false //创建locker属性 6 7 constructor(url, count, start){ 8 this.count = count 9 this.start = start 10 this.url = url 11 } 12 getMoreData(){ 13 //生成器 generator 14 if(!this._getLocker()){ 15 return 16 } 17 this._actualGetData() 18 this._releaseLocker() 19 } 20 21 _actualGetData(){ 22 // 真实获取数据的方法 需要调用Http的request方法 传递一个Object参数对象 23 } 24 25 _getLocker(){ 26 // 获取锁 27 if(this.locker){ 28 return false 29 } 30 this.locker = true 31 return true 32 } 33 _releaseLocker(){ 34 this.locker = false 35 } 36 }
3、获取真实数据的方法封装(刷白,吊天花板,吊灯)
(1)首先需要考虑的是 调用方需要传递请求参数、url、请求方式,需要封装成一个Object对象 这里就是req,将原来的url参数换成req
(2)url 例:v1/spu/latest?start=0&count=10 后面的参数需要进一步的封装,才能使用方便 使用方只需要传递 url:v1/spu/latest 这种就行
(3)getCurrentReq() 方法中,当频繁的进行调用的时候,我们从this.req中取出url,可能导致url重复拼装,最终得到错误的url 解决方法是重新提取出url参数
(4)对返回结果的封装,返回特定的一个数据结构
(5)对于moreData的判断 写在函数中,因为很多地方需要使用,这里的处理方式是将moreData封装成一个属性
(6)处理累加器的accumulator 封装为一个属性 写一个累加的方法进行累加操作
(7)调用请求之前进行moreData的判断
1 import { 2 Http 3 } from "./http"; 4 class Paging { 5 start 6 count 7 req 8 locker = false //创建locker属性 9 url // 添加url属性,解决url重复叠加问题 10 moreData = true 11 12 constructor(req, count, start) { 13 this.count = count 14 this.start = start 15 this.req = req 16 this.url = req.url 17 } 18 async getMoreData() { 19 if(!this.moreData){ 20 return 21 } 22 //生成器 generator 23 if (!this._getLocker()) { 24 return 25 } 26 const data = await this._actualGetData() 27 this._releaseLocker() 28 return data 29 } 30 31 async _actualGetData() { 32 // 真实获取数据的方法 需要调用Http的request方法 传递一个Object参数对象 33 const req = this._getCurrentReq() 34 let paging = await Http.request(this.req) 35 if (!paging) { 36 return null 37 } 38 if (paging.total === 0) { 39 // 不存在分页数据 40 return { 41 empty: true, 42 items: [], 43 moreData: false, 44 accumulator: [] 45 } 46 } 47 // 对moreData进行判断 因为这个变量需要很多地方用 把这个属性封装成属性 48 this.moreData = this._moreData(paging.total_page, paging.page) 49 if (this.moreData) { 50 this.start += this.count 51 } 52 // 累加操作 53 this._accumulate(paging.items) 54 return { 55 empty:false, 56 items:paging.items, 57 moreData:this.moreData, 58 accumulator:this.accumulator 59 } 60 } 61 62 _accumulate(){ 63 // 分页数据累加的方法 64 this.accumulator = this.accumulator.concat(items) 65 } 66 67 _moreData(totalPage, pageNum) { 68 // 总页数 当前页码 69 return pageNum < totalPage - 1 70 } 71 72 _getCurrentReq() { 73 // 封装req参数 74 let url = this.url 75 const params = `start=${this.start}&count=${this.count}` 76 if (url.includes('?')) { 77 url += '&' + params 78 } else { 79 url += '?' + params 80 } 81 thi.req.url = url 82 return this.req 83 } 84 } 85 86 _getLocker() { 87 // 获取锁 88 if (this.locker) { 89 return false 90 } 91 this.locker = true 92 return true 93 } 94 _releaseLocker() { 95 this.locker = false 96 } 97 } 98 99 export { 100 Paging 101 }
4、封装完成
其他操作请自行完成!!!
内容出处:七月老师《从Java后端到全栈》视频课程