H5开发移动应用APP(店铺系列一)
首先,这是个真实的案例,我大兄弟在深圳开汽修店铺,但需要系统来管理日常经营活动,这正不是我擅长的吗?
说干就干,直接后端+web端+移动端来一套,于是紧急赶工,起早摸黑,产出约3万行总量代码,此系统与工作无关,
纯属个人业余开发,所以我敢拿来任意剖析,如果有时间我就出个连载,做一些典型的技术解析。这次说下移动端开发,
考虑到适配和多端问题,还有效率原因,我选择了混合模式,即原生做壳,H5+CSS做内容展现,JS代码实现逻辑,
然后用第三方工具打包生成移动App,我们来看下懒加载模式。
作者原创文章,谢绝一切转载!
本文只发表在"公众号"和"博客园",其他均属复制粘贴!如果觉得排版不清晰,请查看公众号文章。
准备:
Idea2019.03/Gradle6.0.1/JDK11.0.4/Lombok0.28/SpringBoot2.2.4RELEASE/mybatisPlus3.3.0/Soul2.1.2/Dubbo2.7.5
/Mysql8.0.11/Vue2.5/OSS/Hbuilder2.6.1
难度: 新手--战士--老兵--大师
目标:
1.前端展现数据懒加载实现
步骤:
为了遇见各种问题,同时保持时效性,我尽量使用最新的软件版本。代码地址:https://github.com/xiexiaobiao/vehicle-shop-mobile.git
1 本套系统大体情况
后端代码量约1.5万,双前端约1.5万,技术还是很具代表性的,不然就不好意思拿出来说事了,详细可看Git库说明,下图是后端代码量分析:
Web管理界面:
手机端:使用Hbuilder编码,Uniapp框架,再随手捡了几个UI拿来大改了几下,基本形状如下:
2 数据懒加载
比如上图中商品页和订单列表页,数据流量还是很大的,因为里面参杂了图片,如果一上来就一股脑全加载,再搞个前端缓存假分页加载,那你得考虑下用户的
感受!因此需要懒加载,或者叫渐进式加载,必须得结合后端物理分页实现。
思路:后端物理分页,前端首次进页面,先请求一次后端并加载到页面,后续操作中页面滑到底后自动触发后续加载并请求后端,将返回数据累加到前端缓存数组,
再加载到页面,直到数据全部完毕。
首先定义后端(有点不规范,把数据处理写在controller层,没来得及优化):
com.biao.shop.stock.controller.ShopItemController
:
@GetMapping("/item/list") public ObjectResponse<Page<ShopItemEntityDto>> listItem(@RequestParam("pageNum") int current, @RequestParam("pageSize")int size, @RequestParam(value = "itemName",required = false) String itemName, @RequestParam(value = "itemUuid",required = false)String itemUuid, @RequestParam(value = "category",required = false) String category, @RequestParam(value = "brandName",required = false)String brandName, @RequestParam(value = "shipment",required = false) Integer shipment){ int shipmentTemp = Objects.isNull(shipment)? 2: shipment; // 这里的shipment最好设计为int,可以接收 0 1 2 ,boolean型,只能是0 1,前端传来都会自带默认0,导致无法查询无此条件限制的 Page<ShopItemEntityDto> pageInfo = shopItemService.listItem(current,size,itemName,itemUuid,category,brandName,shipmentTemp); ObjectResponse<Page<ShopItemEntityDto>> response = new ObjectResponse<>(); response.setCode(RespStatusEnum.SUCCESS.getCode()); response.setMessage(RespStatusEnum.SUCCESS.getMessage()); response.setData(pageInfo); return response; }
以上代码是controller层,具体后端服务实现我就省略了,请看Git源码,返回给web端是个简单的统一返回封装,
ObjectResponse{"code":200,"message":"SUCCESS","data":{Object}},其数据就是Page类型,具体是MybatisPlus中的
com.baomidou.mybatisplus.core.metadata.Ipage, 包含了数据总量,当前页数和每页的量,来个例子就是下面这样的:
{"code":200,"message":"SUCCESS","data":{"records":[{"idItem":2,"itemUuid":"SP000011","category":"修理","classification":null,"itemName":"雨刮器","sellPrice":60.99,"purchasePrice":45.99,"brandName":"奔驰系列","description":"奔驰系列","shipment":null,"alertQuantity":5,"specification":"35*35cm","unit":"支","picAddr":"https://biao-aliyun-oss-pic-bucket.oss-cn-shenzhen.aliyuncs.com/images/logo-samll.png","stock":null,"sales":null,"discountPrice":null}],"total":23,"size":500,"current":1,"orders":[],"searchCount":true,"pages":1}
那前端就是先定义一个初始请求的量,初始页值必须为 1,然后是每次懒加载的页面数据量,这里有个很隐蔽的地方,
必须保证首次懒加载的页面数据量填满屏幕,否则无法触发屏幕触底上滑加载:
pages\product\list.vue文件
data() { return { // 分页实现页面懒加载 pageInfo:{ "total": 0, "size": 6, // 每次懒加载的页面数据量 "current":1// 首次请求的初始页值,之后每请求一次就累加 1 }, ... }
每次请求数据的方法封装一下:
requesForData:function(){ Request().request({ url:'stock/vehicle/stock/item/list', method: 'get', header:{}, params: { 'pageNum': this.pageInfo.current, 'pageSize': this.pageInfo.size, }, } ).then( res => { let pdtArr = res.data.records; this.goodsList = this.goodsList.concat(pdtArr); // 懒加载机制 --> 加载一次后累加页数 this.pageInfo.total = res.data.total; this.pageInfo.current += 1; } ).catch(err => { console.error('is catch', err) this.err = err; });
以上代码中,要实现懒加载机制,需每次加载一次后累加当前页数,另外使用Array.concat函数,追加到已有的数组后面,这样懒加载基本就成型了!
3 如何触发每次的懒加载?
方法一:uniapp页面有个自带的钩子:
//加载更多 onReachBottom(){ console.log("onReachBottom") this.loadData(); },
方法二:页面模板中的scroll-view元素,加上@scrolltolower事件函数:
<scroll-view class="list-scroll-content" scroll-y @scrolltolower="loadData" :refresher-enabled = "false" >
同时配合:
<uni-load-more :status="tabItem.loadingType"></uni-load-more>
当然,必须有个指示器,告知数据是否全部完毕了, 在loadData方法中最后加一个判断:
//判断是否还有数据, 有改为 more, 没有改为noMore if(this.pageInfo.total > (this.pageInfo.current-1) * this.pageInfo.size){ navItem.loadingType = 'more'; }elseif(this.pageInfo.total <= (this.pageInfo.current-1) * this.pageInfo.size){ navItem.loadingType = 'noMore'; }
收工结束!
后记:
- 懒加载必须配合后端的物理分页机制实现,
- 避免数据前端过滤后导致页面数据没法到达屏幕底部,结果全部数据完毕还没完,但已有的数据却不满一屏,这就不能自动触发事件了!所以,必须禁止懒加载模式下前端数据过滤,即带条件后端查数据,
- 数据加载,要注意与页面渲染的前后顺序,不然页面元素都渲染完了,你数据还没来就尴尬了,上面的后端数据请求可以看到,现在axios都是异步的,返回Promise对象,目前最新的解决办法就是可以使用 async / await 来保证异步代码的执行顺序,但是一定注意 await 后必须是返回Promise对象,否则不保证代码顺序!如果出现页面加载完了,数据还没出来,可以多写几个console.log(),看是否页面渲染在前,数据返回在后。
- 不要看上面我只说了很少,这只是核心和思路,具体实现还是要费点心思的。
全文完!
我的其他文章:
- 1 阿里云平台OSS对象存储
- 2 Dubbo学习系列之十七(微服务Soul网关)
- 3 Docker部署RocketMQ
- 4 流式计算(五)-Flink 计算模型
- 5 流式计算(四)-Flink Stream API 篇二
只写原创,敬请关注