概述
前言
在开始正文之前,不得不吐槽一下,小程序的限制好多。本来想在自定义组件中使用 slot插槽
,让组件更加灵活的,结果 slot
并不能和 for
循环列表一起配合使用,当 slot
写在循环体中时,只能被渲染一次,而使用 抽象节点
来代替的话,每次定制循环都要自定义组件,则更加麻烦,希望微信能做些优化。
瀑布流结构
瀑布流是一种很常见的布局,为了以后可以更加简便的使用,我们在本文会将瀑布流布局封装成一个组件。首先,先介绍一下本文的瀑布流的实现原理。瀑布流有很多种实现方法,我们选用一种较为简单的实现,将每一列瀑布流都作为一个竖向的列表,那么整个瀑布流就是由多个竖向的列表排列组成。然后我们只要将拿到的数据进行分列处理,分成多组数据,交由对应列的的瀑布流进行渲染即可。
瀑布流示例
自定义属性和方法
自定义属性 | 描述 |
---|---|
column-count | 瀑布流的列数 |
horizontal-space | 列与列之间的间距(rpx) |
vertical-space | 上下 item 之间的间距(rpx) |
page-no | 当前页的页码(主要用于分页加载) |
page-src | 当前页的未分组的数据源 |
placeholder | 图片加载时的占位图 |
error | 图片加载失败时显示的图片 |
注:page-no 默认为0,如果没有分页加载的需要,不需要做任何修改,page-src直接接收数据即可。如果有分页加载,page-no 则为当前页码数(从0开始算),page-src 则为当前页的数据数组。
自定义方法 | 描述 |
---|---|
binditemtap | 瀑布流 item 的点击监听 |
github传送门:https://github.com/albert-lii/wx-abui/tree/master/abui/widgets/ab-waterfall
demo传送门:https://github.com/albert-lii/wx-abui/tree/master/pages/waterfall
源码
注:源码中,还引用了
ab-easy-image
组件,如需使用此图片组件,需要另外引入。
- ab-waterfall.wxml
<view class="waterfall">
<view class="waterfall-column" style="width:{{columnWidth}}rpx;margin-right:{{columnNo<(columnArr.length-1)?horizontalSpace:0}}rpx;" wx:for-index="columnNo" wx:for-item="pageArr" wx:for="{{columnArr}}" wx:key="{{columnNo}}">
<block wx:for-index="pageNo" wx:for-item="dataArr" wx:for="{{pageArr}}" wx:key="{{pageNo}}">
<view class="waterfall-column-item" wx:for-index="itemNo" wx:for-item="item" wx:for="{{dataArr}}" wx:key="{{itemNo}}">
<ab-easy-image class="waterfall-column-item__image" style="height:{{item.imgH}}rpx;" src="{{item.imgUrl}}" mode="aspectFill" radius="4px 4px 0 0" placeholder="{{placehodler}}" error="{{error}}" />
<view class="waterfall-column-item__bottom">{{item.title}}</view>
</view>
</block>
</view>
</view>
- ab-waterfall.wxss
.waterfall {
display: flex;
flex-direction: row;
justify-content: center;
width: 100%;
}
.waterfall-column {
display: flex;
flex-direction: column;
width: 100%;
}
.waterfall-column-item {
position: relative;
display: flex;
flex-direction: column;
width: 100%;
margin-bottom: 14rpx;
}
.waterfall-column-item__image {
width: 100%;
font-size: 0;
}
.waterfall-column-item__bottom {
display: flex;
flex-direction: column;
align-content: center;
width: 100%;
font-size: 23rpx;
color: #2e2e2e;
background: white;
border-radius: 0 0 4px 4px;
padding: 8rpx 18rpx 8rpx 18rpx;
box-sizing: border-box;
}
- ab-waterfall.js
Component({
properties: {
// 列数
columnCount: {
type: Number,
value: 2
},
// 列与列之间的间距(rpx)
horizontalSpace: {
type: Number,
value: 14
},
// 上下 item 之间的间距(rpx)
verticalSpace: {
type: Number,
value: 14
},
// 当前页(仅在启用了分页加载时有效)
pageNo: {
type: Number,
value: 0
},
// 当前页的未分组的数据源
pageSrc: {
type: Array,
value: [],
observer: function(newVal, oldVal) {
if (this.data.pageNo == 0) {
this._init(newVal);
} else {
// let _addlist = newVal.slice(oldVal.length,newVal.length);
this._splitData(newVal);
}
}
},
// 图片加载时的占位图
placeholder: {
type: String,
value: null
},
// 图片加载失败时显示的图片
error: {
type: String,
value: null
}
},
data: {
// 列宽
columnWidth: 354,
// 分组后的数据源
columnArr: [],
// 记录每一列的高度
columnHeights: []
},
methods: {
/**
* 初始化
*/
_init: function(list) {
let _columnArr = [];
let _columnHeights = [];
for (let i = 0, len = this.data.columnCount; i < len; i++) {
_columnArr[i] = [];
_columnHeights[i] = 0;
}
this.setData({
columnArr: _columnArr,
columnHeights: _columnHeights
});
// 列数
let _columnCount = this.data.columnCount;
// 列与列之间的间距
let _hspace = this.data.horizontalSpace;
let _query = wx.createSelectorQuery();
let _page = this;
_query.select('.waterfall').boundingClientRect();
// 计算列的宽度
_query.exec(function(rect) {
if (rect == null || rect[0] == null) {
return;
}
let _systemInfo = wx.getSystemInfoSync();
let _screenWidth = _systemInfo.windowWidth;
let _containerWidth = rect[0].width / _screenWidth * 750;
console.log(rect)
let _columnWidth = (_containerWidth - (_columnCount - 1) * _hspace) / _columnCount;
_page.setData({
columnWidth: _columnWidth
});
_page._splitData(list);
});
},
/**
* 分割数据源
*
* @param list 新增加的数据
*/
_splitData: function(list) {
// 列数
let _columnCount = this.data.columnCount;
// 记录每一列的高度,用于判断 item 应该添加在哪一列
//(因为一般情况下,item 中图片之外的高度基本是固定的,所以此处只计算图片高度)
let _columnHeights = this.data.columnHeights;
let _columnArr = new Array(this.data.columnCount);
for (let i in list) {
let _item = list[i];
// 原始图片的宽高
let _oriImgW = parseInt(_item.imgW);
let _oriImgH = parseInt(_item.imgH);
// item 中图片的宽高
let _imgW = this.data.columnWidth;
let _imgH = parseInt(_oriImgH * _imgW / _oriImgW);
_item['imgH'] = _imgH;
// 最短的列的序号
let _minNo = 0;
// 最短的列的高度
let _minCH = _columnHeights[0];
// 分列添加 item
for (let j in _columnHeights) {
if (_columnHeights[j] < _minCH) {
_minNo = j;
_minCH = _columnHeights[j];
}
}
_columnHeights[_minNo] += _imgH;
if (_columnArr[_minNo] == undefined || _columnArr[_minNo] == null) {
_columnArr[_minNo] = [];
}
_columnArr[_minNo].push(_item);
}
for (let i in _columnArr) {
this.setData({
['columnArr[' + i + '][' + this.data.pageNo + ']']: _columnArr[i]
});
}
}
},
})
- ab-waterfall.json
{
"component": true,
"usingComponents": {
"ab-easy-image": "../ab-easy-image/ab-easy-image"
}
}
最后
以上就是舒心火车为你收集整理的微信小程序UI之旅:可分页加载,设置列数的智能瀑布流组件的全部内容,希望文章能够帮你解决微信小程序UI之旅:可分页加载,设置列数的智能瀑布流组件所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复