微信小程序瀑布流最好最簡(jiǎn)單的解決方案

網(wǎng)上能搜到的小程序瀑布流解決方案,要么代碼復(fù)雜、邏輯混亂,要么實(shí)現(xiàn)不了業(yè)務(wù)功能,所以把我在項(xiàng)目中的實(shí)現(xiàn)方案給大家分享下。

最簡(jiǎn)單的實(shí)現(xiàn)方案,不適用有分頁(yè)的場(chǎng)景。

這個(gè)方案簡(jiǎn)單的原因是因?yàn)閮H僅使用了css的屬性。
使用column-count 屬性可以指定頁(yè)面顯示的列數(shù),一般瀑布流都是2列,所以可以定義class

.list-masonry {
  column-count: 2;           //2列
  column-gap: 20rpx;       //列間距
}

界面定義也很簡(jiǎn)單

<view class='list-masonry'>
  <block wx:for="{{goodsList}}" wx:key="{{item.id}}">
    <template is='goodsCard' data="{{data:item}}" />
  </block>
</view>

其中,goodsList為頁(yè)面展示的數(shù)據(jù),goodsCard為瀑布流的卡片,這個(gè)很容易理解。

注意,瀑布流的卡片需要css屬性 display: inline-block; 將卡片設(shè)置為 內(nèi)聯(lián)元素。image 組件設(shè)置縮放模式 mode="widthFix" 來(lái)保持圖片寬高比。

column-count 屬性默認(rèn)是以列的形式來(lái)填充數(shù)據(jù)的。比如我們有20條數(shù)據(jù),1 ~ 10 條數(shù)據(jù)會(huì)展示在左邊第一列,11 ~ 20 條數(shù)據(jù)會(huì)展示在第二列。
如果有分頁(yè),再往數(shù)組中增加20條數(shù)據(jù)后,就會(huì)變成 1 ~ 20 條數(shù)據(jù)會(huì)在左邊,21 ~ 40 條數(shù)據(jù)會(huì)展示在右邊。用戶體驗(yàn)非常差。
由于 column-fill: balance; 填充屬性無(wú)效,無(wú)法指定填充順序?yàn)樾械男问健?/strong>
所以這種實(shí)現(xiàn)方案只能一下加載完所有數(shù)據(jù),不適用于分頁(yè)。

Component實(shí)現(xiàn)瀑布流,功能強(qiáng)大,滑動(dòng)流暢

通過(guò)自定義組件,用自己的思路實(shí)現(xiàn)瀑布流。然后在需要瀑布流的地方直接調(diào)用,方便復(fù)用。

沒(méi)有Demo!! 跟著我的步驟一步一步來(lái),就能輕松實(shí)現(xiàn)。

1. 首先創(chuàng)建瀑布流自定義組件文件。

建議在項(xiàng)目根目錄創(chuàng)建文件夾component,然后在該目錄下創(chuàng)建文件夾WaterFallView,最后在WaterFallView下創(chuàng)建component。(鼠標(biāo)右鍵->新建->Component)。

微信截圖_20180607103451.png
2. 設(shè)計(jì)瀑布流的wxml。

瀑布流的結(jié)構(gòu)簡(jiǎn)單,只有左右2列。所以在設(shè)計(jì)UI的時(shí)候,布局很簡(jiǎn)單。

<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。通過(guò)這兩個(gè)View 來(lái)展示瀑布流的兩列。每個(gè)View對(duì)應(yīng)一個(gè)數(shù)據(jù)源,由此可見(jiàn),這套思路的重點(diǎn)是這個(gè)兩個(gè)數(shù)據(jù)源的處理。每個(gè)View中的template 為瀑布流中的卡片,就不介紹了。
超過(guò)兩列的瀑布流比較少見(jiàn),本篇不考慮,但可用本篇的思路來(lái)實(shí)現(xiàn)。

3. css樣式
.fall-container {
  width: 100%;
  display: flex;
}

.fall-left {
  display: flex;
  flex-direction: column;
}

.fall-right {
  display: flex;
  flex-direction: column;
  margin-left: 20rpx;
}
4. 具體實(shí)現(xiàn)邏輯

根據(jù)上面的 wxml 結(jié)構(gòu),這個(gè)組件的核心邏輯就是如何把要展示的數(shù)據(jù)item 放入leftList、rightList這兩個(gè)數(shù)組中。

如何分配數(shù)據(jù)item?這個(gè)簡(jiǎn)單,我們可以定義2個(gè)變量 leftHight、rightHight,來(lái)分別記錄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ù)圖片的寬高比來(lái)設(shè)置 image組件的寬高。所以如果你們的數(shù)據(jù)沒(méi)有寬高或?qū)捀弑龋茈y實(shí)現(xiàn)瀑布流。雖然可以通過(guò)代碼獲得圖片寬高,但會(huì)對(duì)性能以及用戶體驗(yàn)有很大影響,不推薦這么做??梢院秃笈_(tái)同學(xué)商量下,看如何加上寬高數(shù)據(jù)。

Component有自己生命周期方法,甚至可以象Page一樣,當(dāng)做一個(gè)單獨(dú)的頁(yè)面使用??梢栽谒纳芷诜椒ㄖ蝎@得到瀑布流的寬度,以及圖片的最大高度。

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ì)算瀑布流的最大高度,防止長(zhǎng)圖霸屏
      }
    });
  },

拿到瀑布流的寬度后,就可以根據(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 高度,不超過(guò)最大高度
}

在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>
5. 所有JS代碼
/**
 * 瀑布流組件
 */

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,
      });
    },
  }
})

6. 使用瀑布流

a. 注冊(cè)自定義組件
在使用自定義組件的Page的json文件中聲明要使用的組件

{
    ....
    "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);
  },
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、通過(guò)CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明AI閱讀 16,171評(píng)論 3 119
  • Paypal創(chuàng)始人、Facebook的第一位外部投資者Peter Thiel的這本經(jīng)典創(chuàng)業(yè)書,才讀完第一遍,有所收...
    Thinkpolo閱讀 563評(píng)論 0 3
  • Java關(guān)鍵字final 在設(shè)計(jì)程序時(shí),出于效率或者設(shè)計(jì)的原因,有時(shí)候希望某些數(shù)據(jù)是不可改變的。這時(shí)候可以使用fi...
    獅_子歌歌閱讀 881評(píng)論 1 4
  • 上學(xué)的時(shí)候,對(duì)于上班的生活有過(guò)無(wú)數(shù)次的想象,我認(rèn)為不會(huì)有這么難。可是上了班,我才明白,生活是多么的不容易。...
    阿毛6666666閱讀 241評(píng)論 0 0
  • 不亂于心,不困于情,不畏將來(lái),不念過(guò)往,如此,安好。 但是,放下,看空,這是何等境界,我等凡夫俗子該如何修煉才能得...
    Curtis2019閱讀 484評(píng)論 0 0

友情鏈接更多精彩內(nèi)容