业务需求:
业务需求是给订单列表添加分页功能,也就是上拉加载这种每次只请求加载固定数量的数据。
需求分析:
对业务来说就是简单的分页上拉加载,但是对于技术实现来说,除了要处理分页数据的累加加载,还要处理操作订单返回列表后需要更新列表数据以同步订单最新状态,其中的难点在于后者。
当然你可以直接重新初始化列表数据(请求加载第一页),但是小程序中会记忆数据重载之前的滚动位置,所以要进行处理使页面滚动到顶部。但是如果订单列表数据比较多,用户操作的订单在第一页之后,那么操作订单后返回列表查找之前操作的订单就比较麻烦了,所以如果要求比较高的话,就不能这么操作了。
比较好的体验就是用户操作任何一个订单,如果订单状态改变那么更新列表数据并且返回列表后仍保持在之前操作订单的位置(只有该订单状态改变了,其他都不变)。
实现列表更新订单位置不变的关键代码:
/** * 将列表数据中指定位置的元素替换为操作订单所在的那一页的数据 */ getNewList: function(orderList, curPageList, editPageNum) { if (!orderList || !curPageList || !editPageNum) return; orderList.splice((editPageNum - 1) * this.data.pageSize, this.data.pageSize, ...curPageList) return orderList }
注意:
- 加粗部分为关键代码,其中数组元素替换的索引开始及替换个数根据当前页码及每页显示个数来定义(这里pageNum从1开始);
- ...curPageList 为es6的扩展运算符,这里的作用是将curPageList的每个元素赋给orderList指定位置的元素进行替换。
整体代码:
import http from '../../utils/api.js'//接口请求封装 import coupon from '../../utils/coupon.js'//领取、查看卡券封装 import util from '../../utils/util.js'//点击防重等公用方法封装 Page({ data: { orderList: [], //我的卡券列表 emptyData: '',//接口数据为空标志 pageNum: 1, //页码数,默认从1开始 pageSize: 10, //每页显示条数,默认10条 ispro: false, //默认不在请求中 isnext: false, //默认有下一页 }, /** * 生命周期函数--监听页面加载 */ onLoad: function(options) { this.getCouponList(1); }, /** * 1.获取订单列表 * type 1:初始化加载第一页 2:触底加载 参数为空:查看卡券及领取卡券后重新加载数据(页数不变,替换最后的数据) * editPageNum 领取卡券的订单所属的页数 * 接口调用前根据type进行参数初始化设置 * 接口响应处理中处理是否有下一页标志及列表数据 */ getCouponList: function(type, editPageNum) { let self = this; let { pageSize, pageNum, orderList } = self.data //触底加载带参调用,页数+1,否则页数重置为1 if (type == 1) { //页面初始化加载第一页 pageNum = 1; orderList = [] } else if (type == 2) { //触底加载 pageNum++; } else { //领取卡券订单状态改变后重载列表指定页数据 if (editPageNum) pageNum = editPageNum } let params = { openid: wx.getStorageSync("openid"), pageNum: pageNum, pageSize: pageSize } self.setData({ ispro: true }) http.orderList(params).then(data => { let list = data.order_list //接口返回列表数据 if (list.length > 0) { list.map(item => { item.pageNum = pageNum return item }) if (type == 1) { //初始化加载第一页 orderList = list } else if (type == 2) { //触底加载,追加数据到列表中 orderList = orderList.concat(list) } else { //查看、领取卡券后只替换数组中当前页的数据 orderList = self.getNewList(orderList, list, editPageNum) } let hasNextPage = (data.total / pageSize) > pageNum; //是否有下一页 //给订单项添加所属页数(给订单状态改变重载当前页数据用) self.setData({ orderList: orderList, isnext: hasNextPage, ispro: false, pageNum: pageNum }) } else { self.setData({ ispro: false, emptyData: true }) } }) }, /** * 2.查看订单 */ viewOrder: function(options) { var self = this let { receive_status, order_no, pagenum } = options.currentTarget.dataset if (!order_no || receive_status == 2) return; if (util.preventDuplicateClicks(4)) return; if (receive_status == 0) { //3. 领取卡券 coupon.couponReceive(order_no, function() { self.getCouponList('', pagenum); }) } else if (receive_status == 1) { //4. 查看卡券 coupon.couponView(order_no) } }, /** * 将列表数据中指定位置的元素替换为操作订单所在的那一页的数据 */ getNewList: function(orderList, curPageList, editPageNum) { if (!orderList || !curPageList || !editPageNum) return; orderList.splice((editPageNum - 1) * this.data.pageSize, this.data.pageSize, ...curPageList) return orderList }, /** * 页面上拉触底事件的处理函数 */ onReachBottom: function() { var self = this if (!self.data.ispro && self.data.isnext) { self.getCouponList(2) } } })
如上,其中领取卡券会修改订单状态,所以重载列表数据放在领取卡券成功后的回调中处理,这样,用户完成领取操作返回订单页面就已经完成了数据的重载,基本上无感知的。
这里对获取订单列表的逻辑进行了全面封装,集成了页面初始化数据加载、上拉加载以及领取、查看卡券后列表数据的静默更新加载。虽然整合起来有点耗脑细胞,不过还好,完美的解决了。
注意事项:
这种方法是基于订单总条数不变的情况下才可以使用的,一般情况下用户下单和订单列表订单查看是不会同时操作的,也就不会出现查看订单列表的时候订单总条数会增加的情况。也只有多端登录同时操作才有可能发生,这样的话就需要对列表总条数进行判断,总条数发生改变的话就需要重新加载第一页数据并滚动到底部了。