小程序瀑布流布局(通用方法)

问题

小程序开发受到一些限制,故使用H5和APP的开发思路容易出现问题,做毕业设计需要用到瀑布流布局,看了网上的方法主要有以下三种,但基本都存在问题。

1、使用纯css样式排列出瀑布流布局

核心代码:

  • 父元素:column-count: 2
  • 子元素:break-inside: avoid

局限:只能一次性展示全部数据,不能做动态数据加载,数据显示位置会随数据加载而错位。

案例
https://blog.csdn.net/yuf0812/article/details/80255921
见第一条

2、分成左右两列 根据单条数据索引的奇偶排列出瀑布流布局

核心代码:

  • wx-if="{{index%2==0}}"

局限:当奇数列的元素高度大于或小于偶数列的元素高度时,数据累计过多时会出现较大的高度差,容易出现只有一侧显示数据的情况。

案例
https://blog.csdn.net/yuf0812/article/details/80255921
见第二条

3、分成左右两列 根据图片高度排列出瀑布流布局

核心代码:

  • 略(获取图片高度,依次累计排列)

局限:适用于近有图片或者文字高度固定的情况,当文字高度不固定,数据累积到一定程度时也会出现错位的情况。
注:在仅展示图片或展示文字叠在在图片上时力推该方法。

案例
点击此处查看案例

新方法

利用节点选择器计算出左右栏整体高度,依次插入数据。
适用范围:任何场景均可完美使用。
缺点:对性能有要求,不建议单次加载数据超过20条。

上效果

ewe

html

<view class="left"><block wx:for="{{leftList}}" wx:key="index"><view class="box" style="background:{{item[0]}};height:{{item[1]*2}}rpx">{{item[2]}}</view></block>
</view>
<view class="right"><block wx:for="{{rightList}}" wx:key="index"><view class="box" style="background:{{item[0]}};height:{{item[1]*2}}rpx">{{item[2]}}</view></block>
</view>

css

.left, .right {width: 340rpx;margin-left: 24rpx;float: left;/* background: greenyellow; */
}/* .right{background: palevioletred;
} */.box {margin-bottom: 24rpx;border-radius: 20rpx;color: #fff;font-size: 70px;display: flex;justify-content: center;align-items: center;
}

js

Page({//页面的初始数据data: {total: [], //全部数据leftList: [], //左侧数据rightList: [], //右侧数据},// 生命周期函数--监听页面加载onLoad: function(options) {this.data.total = this.getArr(500) //生成并返回500条数据this.getData() //调用加载数据函数},// 页面上拉触底事件的处理函数onReachBottom: function() {if (this.data.leftList.length + this.data.rightList.length == this.data.total.length) { //左侧已显示数据 + 右侧已显示数据 == 已生成的所有数据wx.showToast({title: '已加载完闭' //提示数据加载完毕})} else {wx.showLoading({title: '加载数据' //提示加载数据})setTimeout(() => {wx.hideLoading() //隐藏加载框this.getData() //调用加载数据函数}, 800)}},// 生成数据数组 参数Len 返回 [[color, height, index],[...],[...]]getArr(Len) {// 生成单条数据function getData() {let color = new String() //随机颜色for (let i = 0; i < 6; i++) {color += (Math.floor(Math.random() * 16)).toString(16)} //生成6位随机16进制数字let num = Math.floor(Math.random() * 150 + 150) //生成随机高度return ['#' + color, num] //返回[color, height]}// 生成数据数组let arr = new Array()for (let i = 0; i < Len; i++) {arr.push(getData().concat(i))}return arr},// 加载数据getData() {let len = this.data.leftList.length + this.data.rightList.length //获取已显示数组长度let con = this.data.total.slice(len, len + 20) //获取添加20条数组数据let leftData = this.data.leftListlet rightData = this.data.rightListfunction selector(Class) { //Promise封装节点查询方法return new Promise(resolve => {wx.createSelectorQuery().select(Class).boundingClientRect(res => {resolve(res.height)}).exec()})}let _this = thisasync function example() {let listHeight = [] //定义一个数组 存放左右两侧高度for (let i = 0; i < con.length; i++) { //遍历瀑布流元素await selector('.left').then(res => {listHeight[0] = res})await selector('.right').then(res => {listHeight[1] = res})console.log('左右高度', listHeight)if (listHeight[0] > listHeight[1]) { //根据左右高度判断渲染至哪一列rightData.push(con[i])} else {leftData.push(con[i])}_this.setData({ //注意:使用的是this.setData 不建议单次加载超过20条leftList: leftData,rightList: rightData})}}example()}})

有用支持一下吧