首先,這是個真實的案例,我大兄弟在深圳開汽修店鋪,但需要系統來管理日常經營活動,這正不是我擅長的嗎?
說干就干,直接后端+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 篇二
只寫原創,敬請關注