双列瀑布流+分页技术的实现(uniapp)
一、双列瀑布流
1、整体思路
- 瀑布流所需展示的数据以数组包对象的形式存储在数组中(以下称为内容数组)
- 将两列瀑布流分成奇数列和偶数列 ,使用flex布局成两列并排的形式.在列内也采用flex,并设置
flex-direction
为column
- 计算出数据库中需要展示在奇数列的数据以及需要展示在偶数列的数据,并分别存储在
oddArr
和evenArr
中,列表展示
2、代码实现
html
html
<view class="waterfall">
<view class="content-list list-left">//奇数列放在左侧
<view class="content-item" v-for="(item,index) in oddArr" :key="index">
...展示单元结构代码
</view>
</view>
<view class="content-list list-right">//偶数列放在右侧
<view class="content-item" v-for="(item,index) in evenArr" :key="index">
...展示单元结构代码
</view>
</view>
</view>
scss
css
.waterfall{
display:flex;
gap:16rpx;
justify-content: space-between;
.content-list{
display:flex;
flex-direction: column;
gap:16rpx;
.content-item{
...展示单元结构样式
}
}
}
javascript
javascript
const oddArr = ref([])
const evenArr = ref([])
const computedArr = ()=>{
oddArr.value = contentArr.value.filter((_,index)=>index%2===1)
evenArr.value = contentArr.value.filter((_,index)=>index%2===0)
}
// contentArr为内容数组
二、分页技术
1、整体思路
分页技术就是在面对大量数据单元需要展示时,一次性全部展示给用户会造成体验感不好,使用了当用户滑动到底部时再继续加载新数据的分批加载的优化。
(1)分页技术最重要的三个变量:
- page:当前在第几页
- pageSize:一页存储几个展示单元
- total:一共有几页
(2)如何实现监控用户滑动触底:
使用scrolltolower
监听用户滑动触底,底层逻辑是:滚动容器的可视区域高度 + 当前滚动条的滚动距离 >= 滚动容器的内容区域高度
(3)整体实现步骤
- 当用户滑动触底时,首先对page和total进行比对,判断数据是否全部加载完成
- 若没有加载完成,page++并传递给后端,请求下一页的数据。将下一页的数据加入已渲染的数据数组,以将新数据在页面上渲染。
- 若加载完成,向用户提示数据全部加载完毕
2、代码实现
html
html
<view class="container">
<topNavigator></topNavigator>//顶部导航栏
<scroll-view
class="scrollview"
scroll-y
@scrolltolower="onScrolltolower"
>
<waterfallContent ref="waterfall"></waterfallContent>//将瀑布流封装成组件
// ref是为组件绑定实例方便调用组件内部声明的方法
</scroll-view>
<bottomTabbar></bottomTabbar>//底部tabbar组件
</view>
scss
css
.container{
height:100vh;
display:flex;
flex-direction: column;
.scrollview{
flex:1;// 重点!让scrollview占据父元素的剩余高度(只有当其父元素是flex容器时才成立)
overflow-y:scroll;
}
}
flex:1
:重点 没有这一条代码scroll-view的高度就没有被确定下来就无法满足触发scrolltolower的条件
Javascript
javascript
//waterfall 组件内部
const postArr = ref([]) //存储新一页的数据
// 存储展示数据
const contentArr = ref([
{
"id": 5,
"title": "北京旅游攻略",
"content": "天安门,颐和园,鸟巢,长城...爱去哪去哪...",
"coverImg": "/src/static/images/活动图片1.png",
"intcircleId": 3,
"createTime": "2025-09-03T14:18:32",
"like": 1,
"comment": 2,
"host": {
"nickname": "云起",
"avatar": "/src/static/images/活动头像1.png"
}
}
])
// 分页相关数据
const pageParams = {
page:1,
pageSize:10,
total:5
}
const finish = ref(false) // 分页数据是否加载完毕
const loadMore = () => {
if(pageParams.page < pageParams.total){
// 加一页
pageParams.page++
// 增加新一页的数据进入内容数组
contentArr.value = [...contentArr.value,...postArr.value]
// 重新计算奇偶数列
computedArr()
// 如果加一页之后到达total了
if(pageParams.page === pageParams.total){
finish.value = true
return
}
finish.value = false
}
}
// 将组件内部的方法暴露出去供父组件使用
defineExpose({
loadMore
})
javascript
// 父组件
// 声明组件实例并在调用组件时绑定
const waterfall = ref()
// 触底时调用子组件声明的加载更多函数
const onScrolltolower = ()=>{
console.log('触底了');
setTimeout(()=>{
waterfall.value.loadMore()
},1000)
}