前言:最近在工作中,實踐了下在 微信小程序中實現瀑布流列表(左右兩欄,動態圖文) ,最終(zhong)的效果還(huan)不錯,所以在此(ci)記(ji)錄,僅供有需要(yao)的人參考。
最終的效果:
補充(chong)說明的(de)(de)是(shi),要做瀑(pu)布流,最(zui)好(hao)是(shi)可(ke)以(yi)知道圖(tu)(tu)片(pian)(pian)(pian)的(de)(de)高度,由接口(kou)下發,來提前占位,否則,即使(shi)是(shi)原(yuan)生app,也會(hui)因為圖(tu)(tu)片(pian)(pian)(pian)的(de)(de)加(jia)載(zai)閃屏使(shi)得不好(hao)的(de)(de)用(yong)戶體驗。在(zai)(zai)小程序中,沒有(you)原(yuan)生app的(de)(de)流式layout控件,所(suo)以(yi)不知道圖(tu)(tu)片(pian)(pian)(pian)寬高的(de)(de)情況(kuang)下,只(zhi)能減少(shao)每(mei)一頁的(de)(de)page_size,在(zai)(zai)加(jia)載(zai)完圖(tu)(tu)片(pian)(pian)(pian)之后,再計算插入的(de)(de)位置(對產(chan)品來說,這可(ke)能是(shi)一個不可(ke)接受(shou)的(de)(de)漫長(chang)過程)
//demo.js
Page({
data:{
renderLists:[]
},
fetchData(){
request(url,params).then(res=>{
const PreData=this.data.renderLists
this.setData({
renderLists:PreData.concat(res)
})
})
}
})
//demo.wxml
<view class="waterfall">
<view class="waterfall__left">
<your-compoent
wx:for="{{renderLists}}"
wx:key="id"
wx:if="{{index % 2 === 0}}"
/>
</view>
<view class="waterfall__right">
<your-compoent
wx:for="{{renderLists}}"
wx:key="id"
wx:if="{{index % 2 === 1}}"
/>
</view>
</view>
| 說明 | 優點 | 缺點 |
|---|---|---|
| 左右列重復wx:for 渲染數據,根據index索引的奇偶性來wx:if | 簡單 | 1.重復for循環。2.如果每個item高度相差較大,很容易造成左右矮的那一欄是部分空白的 |
或許(xu)京東購物小(xiao)程序-首頁就是(shi)這(zhe)樣(yang)做的?(不確定(ding))
這個方式可能就是目前(qian)pc端的實現方式,原(yuan)理都一樣。但是在(zai)小程序(xu)中(zhong),有以下幾(ji)個需要解決的問題
//demo.js
Page({
data:{
leftLists:[],
rightLists:[]
},
onLoad(){
this.leftHeight=0
this.rightHeight=0
},
fetchData(){
request(url,params).then(res=>{
this.generate(res)
})
},
generate(list){
let leftList=[],rightList=[]
list.map(async (item)=>{
//每個item的(de)高(gao)(gao)度=圖片寬(kuan)高(gao)(gao)+內容區域
const itemHeight=getImageHeight(item)+getContentHeight(item)+gap
this.leftHeight>this.rightHeight?rightList.push[item]:leftList.push(item)
})
this.render({leftList,rightList})
},
getImageHeight(){
//如(ru)果知道(dao)圖片寬高(gao),就return item.height
//如果不知(zhi)道,wx.getImageInfo(需要配(pei)合域名)或者通過display:"node" image 然(ran)后 bindload。
},
getContentHeight(){
//文字內容(rong)區域高度(du)固定,直接返回
//不固定,做(zuo)數據映射,例如10個字一行,行高按(an)照設計稿(gao),做(zuo)rpxToPx返(fan)回
},
render(params){
const {leftList,rightList}=params
const preLeft=this.data.leftList;
const preRight=this.data.rightList
this.setData({
leftList:preLeft.concat(leftList),
rightList:preRight.concat(rightList)
},()=>{
const query = this.createSelectorQuery();
query.select('.wrapper__left').boundingClientRect();
query.select('.wrapper__right').boundingClientRect();
query.exec((res) => {
this.leftHeight = res[0].height;
this.rightHeight = res[1].height;
});
})
}
})
//demo.wxml
<view class="waterfall">
<view class="waterfall__left">
<your-compoent
wx:for="{{leftLists}}"
wx:key="id"
/>
</view>
<view class="waterfall__right">
<your-compoent
wx:for="{{rightLists}}"
wx:key="id"
/>
</view>
</view>
| 說明 | 優點 | 缺點 |
|---|---|---|
| 下面↓↓↓ | 性能好,實現的效果好 | (⊙o⊙)… |
注意下面的操作都必須是一個同步獲取的過程,需要異步獲取的都要async await,如果需要異步獲取的數據多,例如圖片,那就是一個耗時操作
可能有小概率會影響我們的計算,這個問題是存在的且可以接受的
createSelectorQuery
可以看下小程序 附近的餐廳 ,效果(guo)很好(hao),他的(de)圖片(pian)寬高是服務器返(fan)回(hui)的(de),文字內容區域(yu)是固定的(de)(標(biao)題只有幾個字,也是兩行(xing))
目前(qian)來說,第(di)三種方案的實(shi)現效果最(zui)好,也是我們正(zheng)在線上使用(yong)的方式,推薦使用(yong)。