微信小程序瀑布流组件

目录

1、什么是瀑布流?

2、核心实现

3、实现过程

 4、应用


1、什么是瀑布流?

瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。

2、核心实现

我们主要通过两个数组进行实现,即分为左右数组。由于每一个图片的高度都是不一样的,需要我们实时计算图片的高度,并判断图片应该添加在哪个数组中。


3、实现过程

一、在components目录下创建名为water-fall的组件,water-fall.wxml主要代码如下:

<!--components/water-fall/water-fall.wxml-->
<view class="wrapper">
  <view class="waterfall" id="list">
    <view id="left-column" class="column">
      <view wx:for="{{leftList}}" wx:key="index" class="item">
        <image src="{{item}}" mode="widthFix" class="pic" wx:if="{{defaultSlot}}" data-src="{{item}}" bindtap="previewImg"/>
        <block wx:else>
            <!-- 自定义内容 -->
        </block>
      </view>
    </view>
    <view id="right-column" class="column">
      <view wx:for="{{rightList}}" wx:key="index" class="item">
        <image src="{{item}}" mode="widthFix" class="pic" wx:if="{{defaultSlot}}" data-src="{{item}}" bindtap="previewImg"/>
        <block wx:else>
           <!-- 自定义内容 -->
        </block>
      </view>
    </view>
  </view>
</view>

        water-fall.scss主要代码如下:
 

/* components/water-fall/water-fall.wxss */
.wrapper {
  padding: 15rpx 0;

  .waterfall {
    height: 100%;
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    justify-content: space-between;

    .column {
      display: flex;
      flex-direction: column;
      flex: 1;
      height: auto;
      word-break: break-all;

      .item {
        width: 98%;
        margin-bottom: 10rpx;

        .pic {
          width: 100%;
          border-radius: 20rpx;
          box-shadow: 0 3rpx 4rpx rgba(0, 0, 0, 0.2);
        }
      }

    }
  }
}

将左右两列数组放置于waterfall 容器中,通过flex布局将两列数组设置为左右两端对齐,并使每列数组column铺满盒子一半。
 

 二、在properties中,设置value接收父组件传入的数据,并在data中分别定义leftList、rightList、tempList、oldTempList四个数组,通过splitData方法对数组进行处理,将每一项分别添加到左leftList、右rightList两列数组中。
        在lifetimes 字段内进行声明attached生命周期函数,并复制传入的数据源value给暂存数组tempList。通过observers监听value数据的变化,其代码如下:

组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。

其中,最重要的生命周期是 created attached detached ,包含一个组件实例生命流程的最主要时间点。

  • 组件实例刚刚被创建好时, created 生命周期被触发。此时,组件数据 this.data 就是在 Component 构造器中定义的数据 data 。 此时还不能调用 setData 。 通常情况下,这个生命周期只应该用于给组件 this 添加一些自定义属性字段。
  • 在组件完全初始化完毕、进入页面节点树后, attached 生命周期被触发。此时, this.data 已被初始化为组件的当前值。这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。
  • 在组件离开页面节点树后, detached 生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则 detached 会被触发
  • 生命周期方法可以直接定义在 Component 构造器的第一级参数中。

    自小程序基础库版本 2.2.3 起,组件的的生命周期也可以在 lifetimes 字段内进行声明(这是推荐的方式,其优先级最高)。

Component({
  options: {
    multipleSlots: true
  },

  properties: {
    value: {
      type: Array,
      value: []
    },
    defaultSlot: {
      type: Boolean,
      value: true
    }
  },

  data: {
    leftList: [],
    rightList: [],
    tempList: [],
    oldTempList: [],
  },

  lifetimes: {
    attached() {
      this.data.tempList = this.cloneData(this.data.value);
      this.splitData();
    },
    detached() {
      // 销毁前的清理操作
    }
  },

  observers: {
    'value': function (nVal) {
      this.setData({
        oldTempList: this.cloneData(nVal),
        tempList: this.findDifferentItems(nVal, this.data.oldTempList)
      });
      this.splitData();
    }
  },

  methods: {
    async splitData() {
      if (!this.data.tempList.length) return;
      let leftRect = await this.getRect('#left-column');
      let rightRect = await this.getRect('#right-column');
      let item = this.data.tempList[0];
      if (!item) return;
      if (leftRect.height <= rightRect.height) {
        let arr = this.data.leftList.concat(item)
        this.setData({
          leftList: arr
        });
      } else {
        let arr = this.data.rightList.concat(item)
        this.setData({
          rightList: arr
        });
      }
      this.data.tempList.splice(0, 1);
      if (this.data.tempList.length) {
        this.splitData();
        return;
      }
    },

    getRect(selector) {
      return new Promise((resolve, reject) => {
        const query = wx.createSelectorQuery().in(this);
        query.select(selector).boundingClientRect();
        query.exec(function (res) {
          if (res && res[0]) {
            resolve(res[0]);
          } else {
            reject('获取节点信息失败');
          }
        });
      });
    },

    cloneData(data) {
      return JSON.parse(JSON.stringify(data));
    },

    clear() {
      this.setData({
        leftList: [],
        rightList: []
      });
    },

    /* 图片预览 */
    previewImg(e) {
      let currentUrl = e.currentTarget.dataset.src
      let imgs = [...this.data.value]
      wx.previewImage({
        current: currentUrl,
        urls: imgs
      })
    },

    /* 数组过滤 */
    findDifferentItems(array1, array2) {
      const uniqueArray = [];

      // 遍历第一个数组
      for (let i = 0; i < array1.length; i++) {
        let found = false;

        // 检查第二个数组中是否存在相同的项
        for (let j = 0; j < array2.length; j++) {
          if (array1[i].id === array2[j].id) {
            found = true;
            break;
          }
        }

        // 如果第二个数组中不存在相同的项,则将其添加到结果数组中
        if (!found) {
          uniqueArray.push(array1[i]);
        }
      }

      return uniqueArray;
    }
  }
});

 4、应用

      一、  page页面中,先在.josn文件中引入water-fall组件:

{
  "usingComponents": {
    "water-fall": "/components/water-fall/water-fall"
  },
  "navigationBarTitleText": "相册"
}

 二、直接在.wxml引入water-fall组件:

  <water-fall value="{{PhotoList}}"></water-fall>

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值