我的实现思路是 将列表拆分成左右两列的数组,然后在追加数据时,获取两个的高度,哪个矮一点我就加到哪个数组里。组件看起来样式比较丑,这是完全自定义的,想要多好看就看你修饰了。
已测试支持的平台
暂不支持的平台
不支持的平台
如果组件不显示,调一下组件clear或update方法即可。如果没列出来的说明没测试到的,不代表不支持
1.首先创建一个waterfall-flow.vue的组件, 然后在template
中写入以下代码
我们用来放置瀑布流的主体内容,name=“left” 是我定义的作用域插槽
的名字,v-bind:leftList="leftList"就是绑定子组件的参数,以供父组件能够直接使用它。
2.样式部分
.flex{
display: flex; /* 使用flex布局 */
width: 100%; /* 宽度占满父组件的宽就好,不设定具体宽 */
height: auto; /* 高度设为由内容自动撑开 */
box-sizing: border-box; /* 这个是必须的,因为我们接下来会接收offset参数来定边距 */
}
.left, .right{
flex: 1; /* 自动分配宽度 */
height: max-content; /* 高度需设为内容的最大高度 */
}
3.props
我们接收几个参数
props: {
list: {
type: Array, // 列表数据
default: []
},
offset: {
type: String, // offset 是offsetW和offsetO的简写,也就是同时包含最外边的边距和元素之间的间距
default: '' // 传有这个属性不为空时offsetW和offsetO将不生效
},
offsetW: {
type: String, // offsetW => offset Within 外边距,两个元素的中间边距
default: '10rpx'
},
offsetO: {
type: String, // offsetO => offset Outside 外边距,两个元素的最外边边距
default: ''
},
},
4.data
定义左右瀑布流的数组,以及当前队列执行到第几项
data(){
return {
leftList: [], // 左边的数据
rightList: [], // 右边的数据
current: 0, // 当前队列执行到第几项了,用于取出list数据,然后分配到对应的leftList还是rightList中
}
},
5.写一个监听器
,监听list的变化,然后执行队列
watch: {
list(val){
// 数据追加,如果只是改变数据重新渲染,length长度一样,那么在这之前应该先调clear方法
if(val.length > (this.leftList.length + this.rightList.length)){
this.pushQueue();
}
}
},
6.现在我们来实现这个队列
pushQueue(){
if((this.leftList.length + this.rightList.length) >= this.list.length){
// 渲染完毕,向外触发load事件
this.$emit('load', {
total: this.current,
leftList: this.leftList,
rightList: this.rightList
});
this.current--;
return;
};
// 这里得要加个定时器,要不然有时候获取query信息是无的
setTimeout(() => {
let query = uni.createSelectorQuery().in(this);
query.select('#left').boundingClientRect();
query.select('#right').boundingClientRect();
query.exec((res) => {
let leftHeight = res[0].height; // 获取左边列表的高度
let rightHeight = res[1].height; // 获取右边列表的高度
leftHeight <= rightHeight ? this.leftList.push(this.list[this.current]) : this.rightList.push(this.list[this.current]);
this.current++;
this.pushQueue(); // 执行下一个队列
});
}, 300);
},
就是这么简单,大工告成了!下面是瀑布流组件全部的代码
,并且添加clear
和update
方法,用于数据清除
我参考了 uView 1.x
版本的瀑布流组件的写法,所以看起来是差不多的。我假设你已经会引入组件了,那么现在来写dom
{{ item.title }}
{{ item.title }}
很关键
!!!.demo-warter{
width: 100%; // 此为必须,让其容器自适应组件动态分配的宽度
height: auto; // 除了不能设置固定值,其他皆可,通常设为auto就好了
background-color: #ffaaff; // 盒子的背景色...
border-radius: 10rpx; // 盒子圆角...
overflow: hidden; // 用于显示圆角效果的...
// 更多样式优化自行添加...
}
// nth-child(n+2) 这种写法快手小程序不支持,可以自己在template中用js判断写style
.demo-warter:nth-child(n+2){
margin-top: 10rpx; // 元素的上边距,从第二个元素开始出现10rpx,不设置它们将会挨在一起
}
.demo-warter image{
width: 100%; // 此为必须,必须将图片的宽度设为100%,好让它自适应父容器显示
}
ok, 一个瀑布流组件的基本使用已经可以了,接下来是需要注意的地方
(父组件)
// 下拉刷新
onPullDownRefresh(){
this.list = [];
/**
* 数据被置空时,this.$refs.myWaterfallFlow.clear()方法是必须要调的
* 如果是强制渲染的场景请使用this.$refs.myWaterfallFlow.update(), 例如排序
* */
this.$refs.myWaterfallFlow.clear(); // 需要注意的地方就是这里,如果列表被置为空,例如下拉刷新时,请调用内部方法清除一下瀑布流的列表
setTimeout(() => {
this.getList();
uni.stopPullDownRefresh();
}, 500);
}
代码我已放入仓库,点击此处来访问~
我在仓库里用两种方式实现了瀑布流,这个例子讲的是waterfall-flow2
的组件
如有写的不对之处,还请大佬不吝赐教
,非常感谢!本人目前还在学习当中,不喜勿喷
。
如有不明确之处还请留言,或添加我的微信:pipiping_
23年3月17日更新分割线