uniapp小程序瀑布流升级版
前言
上文使用双列布局实现了简单版的瀑布流,但是在小程序上面由于css不兼容,以及一次请求数据过多,图片高度不确定,会导致下滑加载数据过程中,页面上下抽搐,卡顿。
于是我换了一种相对复杂的方式,来完成小程序瀑布流的实现。
实现思路
- 使用float布局,分为左侧和右侧两个列表
- 在请求拿到分页数据后,遍历数据,计算leftBox 和 rightBox的高度。
- 比较高度,将数据item push到高度小的那个盒子
代码
新建WaterfallList文件夹,及文件夹下的index.vue文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65<template>
<view class="waterfallList">
<view id="leftList" class="leftList">
<ProductItem v-for="item in leftData" :key="item.id" :productData="item"></ProductItem>
</view>
<view id="rightList" class="rightList">
<ProductItem v-for="item in rightData" :key="item.id" :productData="item"></ProductItem>
</view>
</view>
</template>
<script>
import ProductItem from "./ProductItem.vue";
export default {
components: {ProductItem},
data() {
return {
leftData: [],
rightData: []
};
},
methods: {
async loadMore(data) {
for (const item of data) {
// 获取高度
const leftListHeight = await this.getDomHeight('#leftList')
const rightListHeight = await this.getDomHeight('#rightList')
if (leftListHeight < rightListHeight) {
this.leftData.push(item)
} else {
this.rightData.push(item)
}
}
},
getDomHeight(selector) {
return new Promise(resolve => {
uni.createSelectorQuery().in(this).select(selector).fields(
{
size: true,
},
(data) => {
resolve(data.height)
}
).exec();
})
}
}
}
</script>
<style lang="scss" scoped>
.waterfallList {
overflow: hidden;
}
.leftList {
width: 48%;
float: left;
}
.rightList {
width: 48%;
float: right;
}
</style>ProductItem组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138<template>
<view class="productItem">
<image class="productImage" :src="productData.pic" lazy-load="true" mode="widthFix"></image>
<view class="container">
<view class="productName">{{ productData.name }}</view>
<view class="priceBox">
<view>
<text class="priceIcon">¥</text>
{{ productData.price }}
<text class="unit" v-if="productData.tag">/箱</text>
</view>
<view class="iconBox">
<uni-icons color="#fff" type="cart" size="32rpx"></uni-icons>
</view>
</view>
<view v-if="productData.tag" class="tag">
<view class="iconBoxTag">
<image class="medalsIcon" :src="getStatic('/index/medals.png')" mode="scaleToFill"></image>
</view>
<view class="tagText">{{productData.tag}}</view>
<view class="tagOrder">TOP 1</view>
</view>
</view>
</view>
</template>
<script>
import {getStatic} from "@/utils/global";
export default {
methods: {getStatic},
props: {
productData: {
type: Object,
default: {}
}
},
data() {
return {};
}
}
</script>
<style lang="scss" scoped>
.productItem {
width: 344rpx;
border-radius: 15rpx;
overflow: hidden;
background-color: #fff;
margin-bottom: 20rpx;
break-inside: avoid;
}
.productItem .productImage {
width: 344rpx;
}
.container {
padding: 0 22rpx 30rpx 22rpx;
font-size: 24rpx;
.productName {
color: #212121;
font-size: 28rpx;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
overflow:hidden;
/*! autoprefixer: off */
-webkit-box-orient: vertical;
}
.priceBox {
color: #ff0000;
font-size: 40rpx;
line-height: 32rpx;
font-weight: bold;
padding-top: 22rpx;
display: flex;
justify-content: space-between;
align-items: center;
.priceIcon {
font-size: 26rpx;
}
.unit {
font-size: 28rpx;
color: #CFCFCF;
}
.iconBox {
width: 52rpx;
height: 52rpx;
border-radius: 50%;
overflow: hidden;
background: linear-gradient( 180deg, #FA2C19 0%, #FE5617 100%);
display: flex;
justify-content: center;
align-items: center;
}
}
.tag {
margin-top: 20rpx;
width: 304rpx;
height: 48rpx;
background: #FAF5EC;
border-radius: 8rpx;
display: flex;
align-items: center;
.iconBoxTag {
width: 52rpx;
height: 48rpx;
overflow: hidden;
background: linear-gradient( 166deg, #E3CB8B 0%, #D5A443 100%);
border-radius: 8rpx 0rpx 8rpx 8rpx;
display: flex;
align-items: center;
justify-content: center;
.medalsIcon {
width: 36rpx;
height: 36rpx;
}
}
.tagText{
margin-left: 16rpx;
font-weight: 500;
font-size: 26rpx;
color: #C89839;
}
.tagOrder {
margin-left: 8rpx;
font-size: 26rpx;
color: #C89839;
font-weight: 500;
}
}
}
</style>在index中引入WaterfallList组件,通过this.$refs调用WaterfallList组件的loadMore方法,将请求的分页数据传入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36// 下滑加载推荐商品数据
<template>
<WaterfallList ref="waterfallRef"></WaterfallList>
</template>
<script >
import WaterfallList from '@/components/WaterfallList/index.vue'
export default {
components: {
WaterfallList
},
data() {
return {
pageNum: 1,
loadingType: 'more'
}
},
methods: {
async loadListData() {
if (this.loadingType === 'more') {
this.loadingType = 'loading'
// 请求数据
const { data } = await fetchProductList({pageNum: this.pageNum, pageSize:10})
if (data.length === 0) {
this.loadingType = 'nomore'
return
}
// 调用loadMore更新列表
await this.$refs.waterfallRef.loadMore(data)
this.pageNum++
this.loadingType = 'more'
}
},
}
}
</script>
- 标题: uniapp小程序瀑布流升级版
- 作者: DansRoh
- 创建于 : 2024-09-10 00:00:00
- 更新于 : 2024-09-10 13:31:07
- 链接: https://blog.shinri.me/2024/09/10/41_uniapp小程序实现瀑布流升级版/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论