一、list教程
1)簡單場景:在頁面中實現 長列表 或者 屏幕滾動 等效果時,可以使用list。(平常會使用div,但是當DOM結構復雜時,滾動頁面會出現卡頓現象,因為Native無法復用div組件實現的列表元素)
而list由於會復用相同的type屬性的list-item,使得更加流暢。
使用list 組件代碼如下:
<template>
<!--列表實現-->
<list class="tutorial-page" onscrollbottom="loadMoreData">
<!--商品列表-->
<block for="{{productList}}">
<list-item type="product" class="content-item" onclick="route($item.url)">
.........
</list-item>
</block>
<!--加載更多,type屬性自定義命名為loadMore-->
<list-item type="loadMore" class="load-more">
<progress type="circular">
<text>加載更多</text>
</list-item>
</list>
</template>
要實現DOM片段的復用,要求相同type屬性的DOM結構完全相同。所以,設置相同type屬性的list-item是優化列表滾動性能的關鍵;
注意:
list-item內不能再嵌套list
list-item 的type屬性為必填屬性
list-item內部需謹慎使用if指令或for指令,因為相同的type屬性的list-itemde DOM結構必須完全相同,而使用if指令或for指令會造成DOM結構差異;可以使用show指令代替if指令
2) 復雜場景:一個商品列表頁,圖片位於左邊和圖片位於右邊的商品交錯顯示
列表中的列表元素可以分為三類,設置三種不同type屬性的 list-item。分別為:
a)圖片在左,文字在右的list-item,type屬性自定義命名為productLeft;
b ) 圖片在右,文字在左的list-item,type屬性自定義命名為productRight;
c)加載更多 list-item,type屬性自定義命名為loadMore
<template>
<!--列表實現-->
<list class="tutorial-page" onscrollbottom="loadMoreData">
<block for="{{productList}}">
<!--圖片在左,文字在右的list-item,type屬性自定義命名為productLeft-->
<list-item type="productLeft" class="content-item" onclick="route($item.url)" if="{{$idx%2===0}}">
.........
</list-item>
<!--圖片在右,文字在左的list-item,type屬性自定義命名為productRight-->
<list-item type="productRight" class="content-item" onclick="route($item.url)" if="{{$idx%2===1}}">
.........
</list-item>
</block>
<!--加載更多,type屬性自定義命名為loadMore-->
<list-item type="loadMore" class="load-more">
<progress type="circular">
<text>加載更多</text>
</list-item>
</list>
</template>
list組件性能優化: 精簡DOM層級,復用list-item,細粒度划分list-item,關閉scrollpage四個方面;
其中,精簡DOM層級,復用list-item是使用list組件必須遵循的優化原則,細粒度划分list-item,關閉scrollpage適用於部分場景;
細粒度划分的list-item,即列表中相同的DOM結構划分為盡可能小的列表元素(即list-item)
關閉scrollpage:list組件支持屬性scrollpage,默認關閉,標志是否將頂部頁面中非list元素隨list一起滾動。開啟scrollpage會降低list渲染性能,
因此在開發者開啟scrollpage前,推薦先嘗試將頂部頁面中非list的元素,作為一種或多種type屬性的list-item,移入list從而達到關閉scrollpage提高渲染性能的目的;
3)list-item懶加載
懶加載,簡稱 lazyload,本質上是按需加載;
在傳統頁面中,常用的lazyload優化網頁的性能:
實現:不加載全部頁面資源,當資源即將呈現在瀏覽器 可視區域 時,再加載資源;
優點:加快渲染的同時避免流量浪費
在框架中,開發者也可以使用lazy-load概念優化列表的渲染:
實現:提前fetch請求足夠的列表數據保存在內存變量memList中,當list滾動到底部時,從memList中提取部分數據來渲染list-item。當memList中數據不足時,提前fetch請求數據,填充memList
優點:每次網絡請求與頁面渲染的數量不一致,減少首屏渲染占用的JS執行時間,較少渲染后續list-item的等待時間;
上述實現代碼:
import { dataComponentListLazyload } from '../../Common/js/data';
//模擬fetch請求數據
function callFetch(callback){
setTimeout(function(){
callback(dataComponentListLazyload);
},500)
}
//內存中存儲的列表數據
let memList = [];
export default{
private:{
productList:[],
hasMoreData: true,
size:10,//每次 渲染數據的商品數
isLoadingData:false,//是否正在fetch請求數據
},
onInit(){
this.$page.setTitleBar({ text:'list-item懶加載'});
this.loadAndRender();//獲取數據並渲染列表
},
loadAndRender(doRender = true ){
this.isLoadingData = true;
//重新請求數據並根據數據模式判斷是否需要渲染列表
callFetch(function(resList){
this.isLoadingData = false;
if(!resList){
console.info('數據請求錯誤');
}
else if(!resList.length){
this.hasMoreData = false;
}else{
memList = memList.concat(resList);
if(doRender){
this._renderList();
}
}
}.bind(this))
},
_renderList(){
if(memList.length>0){
const list = memList.splice(0,this.size);
this.productList = this.productList.concat(list);
}
if(memList.length<=this.size){
//提前請求新的數據
this.loadAndRender(false);
}
},
renderMoreListItem(){
if(!isLoadingData){
this._renderList();
}
}
}
4)吸頂效果
傳統頁面的實現思路
a)當手指向上滑動超過吸頂元素的初始位置,把吸頂元素固定在頂部;
b)當手指向下滑動到底吸頂元素的初始位置時,取消吸頂元素在頂部的固定;
吸頂在傳統web頁面中的實現思路是監聽scroll事件,當頁面滾動到一定位置時,做一些事情來改變吸頂元素在窗口中的位置;
框架的實現思路
注意:在框架中scroll僅適用於list組件,且獲取的值是滾動的相對坐標值,在使用時,需要通過累加來獲取當前滾動位置的絕對坐標;
並且scroll在列表滾動時會被高頻觸發,存在潛在性能問題;
采用stack組件作為整個頁面的容器,stack組件的特性為:每個直接子組件按照先后順序依次堆疊,覆蓋前一個子組件;
“吸頂”條件:
a)當頁面向下滾動到 頂部元素 消失在視野時,吸頂元素 需要固定在頂部,因此,監聽 頂部元素的disappear事件,顯示mask;
b)當頁面向上滾動到 頂部元素 出現雜視野時,吸頂元素需要取消固定,因此,監聽 頂部元素的appear事件,隱藏mask
