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 篇二
只写原创,敬请关注

H5开发移动应用APP(店铺系列一)的更多相关文章
- Anyoffice -HTML5大赛 悦心(基于H5开发安卓音乐app)-项目总结
项目在线演示地址:http://rose111.applinzi.com/ github 地址:欢迎star https://github.com/midoxinxin/YueX-Music 悦心,一 ...
- MUI框架开发HTML5手机APP(一)--搭建第一个手机APP
前 言 JRedu 随着HTML5的不断发展,移动开发成为主流趋势!越来越多的公司开始选择使用HTML5开发手机APP,而随着手机硬件设备配置的不断提升,各种开发框架的不断优化,也使着H5开发的 ...
- MUI框架开发HTML5手机APP(一)--搭建第一个手机APP(转)
出处:http://www.cnblogs.com/jerehedu/p/7832808.html 前 言 JRedu 随着HTML5的不断发展,移动开发成为主流趋势!越来越多的公司开始选择使用H ...
- MUI框架开发HTML5手机APP
出处:http://www.cnblogs.com/jerehedu/p/7832808.html 前 言 JRedu 随着HTML5的不断发展,移动开发成为主流趋势!越来越多的公司开始选择使用H ...
- 原生开发、H5开发、混合移动开发的优缺点
一.原生开发(Native App开发) 原生开发,是在Android.IOS等移动平台上利用官方提供的开发语言.开发类库.开发工具进行App开发.比如Android是利用Java.Eclipse.A ...
- 关于APP,原生和H5开发技术的争论
App的开发技术,目前流行的两种方式,原生和Html5.原生分了安卓平台和ios平台(还有小众的黑莓.死去的塞班就不说了),H5就是Html5. 目前争论不休的问题,在早先前争论CS,BS架构的软件系 ...
- H5外包团队 H5开发微信APP的优势有哪些
H5外包团队 H5开发微信APP的优势有哪些
- 用H5开发微信还是开发APP?
用H5开发微信还是开发APP? 随着技术的飞速发展,HTML第五版技术标准的更新,在移动端,由于其相对较低的开发成本及强大的跨平台运行能力,越来越多的信息型产品也开始选择这样轻量级的H5页面进行快速迭 ...
- 关于APP,原生和H5开发技术的争论 APP开发技术选型判断依据
关于APP,原生和H5开发技术的争论 App的开发技术,目前流行的两种方式,原生和Html5.原生分了安卓平台和ios平台(还有小众的黑莓.死去的塞班就不说了),H5就是Html5. 目前争论不休的问 ...
随机推荐
- zcat|subprocess.check_all|subprocess.Popen|gzip|readline()
#!/usr/bin/python from subprocess import check_call import subprocess import gzip ''' $ zcat 160121_ ...
- form提供的两种数据传输方式 get和post method=”post“和method=”get”
虽然它们都是数据的提交方式,但是在实际传输时确有很大的不同,并且可能会对数据产生严重的影响.虽然为了方便的得到变量值,Web容器已经屏蔽了二者的一些差异,但是了解二者的差异在以后的编程也会很有帮助的. ...
- Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080
解决办法: 两个方案:1.注册处理函数时,用如下方式,明确声明为不是被动的window.addEventListener('touchmove', func, { passive: false }) ...
- 如何消除img间的默认间隙
方案一:div{font-size:0};方案二:img{ display:block};方案三:img{vertical-align:top;}方案四:div{ margin-bottom:-3px ...
- CF-1144F-Graph Without Long Directed Paths
题意: 给出一个无向联通图,要求你给出每条边的方向,使得无论从哪个点出发最多只能走一条边: 思路: 对于每个点,要么出度为0,要么入度为0即可.所以这就是一个判断二分图. 二分图 #include & ...
- 使用Spring AOP 实现日志管理(简单教程)
有时候,我们在做项目时会遇到这样的需求: 给XXX.java中的所有方法加上指定格式的日志输出. 针对这种指定类.或者指定方法进行共性操作的功能,我们完全可以使用Spring AOP来实现. 本文使用 ...
- leetcode第32题:最长有效括号
关于括号匹配或生成的问题,首先想到的是栈. 本题易错点:返回值为连续有效()的长度, 即()(()这种情况下,返回值为2 # 去除字符串首的连续)和字符串尾得连续( while True: if no ...
- python爬虫心得(第一天)
爬虫是什么? 我个人觉得用简单通俗的话来说就是在浏览网页的过程中将有价值的信息下载到本地硬盘或者是储存到数据库中的行为. 爬虫的基础认知 可以参考此链接:https://www.imooc.com/a ...
- 从Surface 3发布 看微软快速转向的根由
3发布 看微软快速转向的根由" title="从Surface 3发布 看微软快速转向的根由"> 平地一声惊雷起,微软突然送惊喜!在毫无征兆的情况下,微软突然发布一 ...
- 很全很全的 JavaScript 模块讲解
模块通常是指编程语言所提供的代码组织机制,利用此机制可将程序拆解为独立且通用的代码单元.所谓模块化主要是解决代码分割.作用域隔离.模块之间的依赖管理以及发布到生产环境时的自动化打包与处理等多个方面. ...