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';
}

收工结束!

后记:

  1. 懒加载必须配合后端的物理分页机制实现,
  2. 避免数据前端过滤后导致页面数据没法到达屏幕底部,结果全部数据完毕还没完,但已有的数据却不满一屏,这就不能自动触发事件了!所以,必须禁止懒加载模式下前端数据过滤,即带条件后端查数据,
  3. 数据加载,要注意与页面渲染的前后顺序,不然页面元素都渲染完了,你数据还没来就尴尬了,上面的后端数据请求可以看到,现在axios都是异步的,返回Promise对象,目前最新的解决办法就是可以使用 async / await 来保证异步代码的执行顺序,但是一定注意 await 后必须是返回Promise对象,否则不保证代码顺序!如果出现页面加载完了,数据还没出来,可以多写几个console.log(),看是否页面渲染在前,数据返回在后。
  4. 不要看上面我只说了很少,这只是核心和思路,具体实现还是要费点心思的。

全文完!


我的其他文章:

       

     只写原创,敬请关注

posted @ 2020-03-09 22:16  甲由崽  阅读(1515)  评论(10编辑  收藏  举报