網上能搜到的小程序瀑布流解決方案,要么代碼復雜、邏輯混亂,要么實現不了業務功能,所以把我在項目中的實現方案給大家分享下。 最簡單的實現方案,不適用有分頁的場景。
這個方案簡單的原因是因為僅僅使用了css的屬性。 .list-masonry { column-count: 2; //2列 column-gap: 20rpx; //列間距 }
界面定義也很簡單 <view class='list-masonry'> <block wx:for="{{goodsList}}" wx:key="{{item.id}}"> <template is='goodsCard' data="{{data:item}}" /> </block> </view>
其中,goodsList為頁面展示的數據,goodsCard為瀑布流的卡片,這個很容易理解。 注意,瀑布流的卡片需要css屬性 display: inline-block; 將卡片設置為 內聯元素。image 組件設置縮放模式 mode="widthFix" 來保持圖片寬高比。
column-count 屬性默認是以列的形式來填充數據的。比如我們有20條數據,1 ~ 10 條數據會展示在左邊第一列,11 ~ 20 條數據會展示在第二列。 通過自定義組件,用自己的思路實現瀑布流。然后在需要瀑布流的地方直接調用,方便復用。 沒有Demo!! 跟著我的步驟一步一步來,就能輕松實現。
建議在項目根目錄創建文件夾component,然后在該目錄下創建文件夾WaterFallView,最后在WaterFallView下創建component。(鼠標右鍵->新建->Component)。
瀑布流的結構簡單,只有左右2列。所以在設計UI的時候,布局很簡單。 <view class='fall-container'> <!-- 左邊一列 --> <view class='fall-left'> <block wx:for="{{leftList}}" wx:key="{{item.id}}"> <!--瀑布流內容卡片--> <template is='goodsCard' data="{{data:item}}" /> </block> </view> <!--右邊一列 --> <view class='fall-right'> <block wx:for="{{rightList}}" wx:key="{{item.id}}"> <!--瀑布流內容卡片--> <template is='goodsCard' data="{{data:item}}" /> </block> </view> </view>
左右兩邊,一邊一個View。通過這兩個View 來展示瀑布流的兩列。每個View對應一個數據源,由此可見,這套思路的重點是這個兩個數據源的處理。每個View中的template 為瀑布流中的卡片,就不介紹了。
.fall-container { width: 100%; display: flex; } .fall-left { display: flex; flex-direction: column; } .fall-right { display: flex; flex-direction: column; margin-left: 20rpx; }
根據上面的 wxml 結構,這個組件的核心邏輯就是如何把要展示的數據item 放入leftList、rightList這兩個數組中。 如何分配數據item?這個簡單,我們可以定義2個變量 leftHight、rightHight,來分別記錄leftList、rightList數組中圖片的高度(可以理解為左邊View、右邊View的高度,其實只是圖片的高度,但已滿足瀑布流的的需求)。當leftHight 大于 rightHight時,把數據放入rightList,并讓rightHight疊加數據中圖片的高度。當rightHight大于 leftHight 時,把數據放入leftList,并讓leftHight 疊加數據中圖片的高度。 if (leftHight == rightHight) { //第1個item放左邊 leftList.push(tmp); leftHight = leftHight + tmp.itemHeight; } else if (leftHight < rightHight) { leftList.push(tmp); leftHight = leftHight + tmp.itemHeight; } else { rightList.push(tmp); rightHight = rightHight + tmp.itemHeight; }
瀑布流展示圖片的時候,需要知道圖片的寬高,然后根據圖片的寬高比來設置 image組件的寬高。所以如果你們的數據沒有寬高或寬高比,很難實現瀑布流。雖然可以通過代碼獲得圖片寬高,但會對性能以及用戶體驗有很大影響,不推薦這么做??梢院秃笈_同學商量下,看如何加上寬高數據。
Component有自己生命周期方法,甚至可以象Page一樣,當做一個單獨的頁面使用??梢栽谒纳芷诜椒ㄖ蝎@得到瀑布流的寬度,以及圖片的最大高度。 attached: function () { //第一個生命周期方法 wx.getSystemInfo({ success: (res) => { let percentage = 750 / res.windowWidth; //750rpx/屏幕寬度 let margin = 20 / percentage; //計算瀑布流間距 itemWidth = (res.windowWidth - margin) / 2; //計算 瀑布流展示的寬度 maxHeight = itemWidth / 0.8 //計算瀑布流的最大高度,防止長圖霸屏 } }); },
拿到瀑布流的寬度后,就可以根據圖片的寬高比,計算出 image 組件的寬高。 let tmp = listData[i]; //單條數據 tmp.width = parseInt(tmp.width); //圖片寬度 tmp.height = parseInt(tmp.height); //圖片高度 tmp.itemWidth = itemWidth //image 寬度 let per = tmp.width / tmp.itemWidth; //圖片寬高比 tmp.itemHeight = tmp.height / per; //image 高度 if (tmp.itemHeight > maxHeight) { tmp.itemHeight = maxHeight; //image 高度,不超過最大高度 }
在template中,image的寬高需要聲明下。單位是px,不是rpx <image class='card-img' mode='aspectFill' style='width:{{data.itemWidth}}px;height:{{data.itemHeight}}px;' src='{{data.img}}' lazy-load> </image>
/** * 瀑布流組件 */ var leftList = new Array();//左側集合 var rightList = new Array();//右側集合 var leftHight = 0, rightHight = 0, itemWidth = 0, maxHeight = 0; Component({ properties: {}, data: { leftList: [],//左側集合 rightList: [],//右側集合 }, attached: function () { wx.getSystemInfo({ success: (res) => { let percentage = 750 / res.windowWidth; let margin = 20 / percentage; itemWidth = (res.windowWidth - margin) / 2; maxHeight = itemWidth / 0.8 } }); }, methods: { /** * 填充數據 */ fillData: function (isPull, listData) { if (isPull) { //是否下拉刷新,是的話清除之前的數據 leftList.length = 0; rightList.length = 0; leftHight = 0; rightHight = 0; } for (let i = 0, len = listData.length; i < len; i++) { let tmp = listData[i]; tmp.width = parseInt(tmp.width); tmp.height = parseInt(tmp.height); tmp.itemWidth = itemWidth let per = tmp.width / tmp.itemWidth; tmp.itemHeight = tmp.height / per; if (tmp.itemHeight > maxHeight) { tmp.itemHeight = maxHeight; } if (leftHight == rightHight) { leftList.push(tmp); leftHight = leftHight + tmp.itemHeight; } else if (leftHight < rightHight) { leftList.push(tmp); leftHight = leftHight + tmp.itemHeight; } else { rightList.push(tmp); rightHight = rightHight + tmp.itemHeight; } } this.setData({ leftList: leftList, rightList: rightList, }); }, } })
a. 注冊自定義組件 { .... "usingComponents": { "waterFallView": "../../component/WaterFallView/WaterFallView" } }
b. 在 wxml 中添加組件,并加上 id <waterFallView id='waterFallView'> </waterFallView> c. 在JS中找到組件,并調用fillData() 方法。下拉刷新時 isFull 傳 true。 fillData: function (isFull,goods){ let view = this.selectComponent('#waterFallView'); view.fillData(isFull, goods); }, |