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