本次主要实现的功能是一个三列的表格瀑布流布局。
实现效果图:
功能主要的重点就是每次拿到一条数据时,找出三列中高度最小的,然后往高度最小的插入这条数据。
首先先声明了几个变量做为数据处理
data() {
return {
columnCount: 3, // 默认列数
columnHeights: [], // 记录每列的高度
itemMargin: 25, // 元素间隙
columnData: [[], [], []], // 三列数据
}
},
因为做的是三列瀑布流,这里先定了3,同时需要获取到屏幕的宽度并进行平均分配,而为了适配不同的分辨率,写了一个rpx转换为px的方法,宽度的获取代码如下。
methods中写了一个rpx转换方法
adaptScreen(rpx) {
return (uni.getSystemInfoSync().windowWidth * Number.parseInt(rpx)) / 750
},
computed中写了一个获取宽度的方法
getItemStyle() {
let swiperWidth = parseInt(uni.getSystemInfoSync().windowWidth - this.adaptScreen(35))
let swiperItem = parseInt((swiperWidth - (this.columnCount - 1) * this.itemMargin) / this.columnCount);
return { width: swiperItem + 'px' };
},
核心代码
瀑布流的实现,我们需要每次都获取到最小的高度,然后往其中插入数据
首先调取接口获取到后端数据后,进行一个遍历循环,这里的this.mealList值是后端给的数据,循环中找出最小的高度的下标,然后往对应的this.columnData[对应的最小高度的下标]中插入数据,同时要更新下三列的高度(这里更新列的高度是拿到后端返回的表格数据的长度+表格标题)。
this.mealList.forEach((items) => {
const columnIndex = this.getMinHeightColumnIndex();
const columnHeight = this.columnHeights[columnIndex];
const newItemHeight = (items.list.length + 1);
this.columnHeights[columnIndex] = columnHeight + newItemHeight;
this.columnData[columnIndex].push(items);
});
// 获取最小高度的列索引
getMinHeightColumnIndex() {
let minHeight = this.columnHeights[0];
let minIndex = 0;
for (let i = 1; i < this.columnCount; i++) {
if (this.columnHeights[i] < minHeight) {
minHeight = this.columnHeights[i];
minIndex = i;
}
}
return minIndex;
},
全部代码如下
<template>
<view class="home">
<view class="homeBox">
<view class="contentBox">
<view class="mainContent">
<view class="swiperTable">
<view v-for="(columns, index) in columnCount" :style="[getItemStyle]" ref="columns" id="columns"
:key="`swipers-1-${columns + 1}`">
<view v-for="(datas) in columnData[index]" :key="datas.typeName" class="columnDataBox">
<view class="tableTitle">{{ datas.typeName ? datas.typeName : '未分类' }}</view>
<view class="tableContent" v-for="(nameList) in datas.list" :key="nameList.code">
{{ nameList.name }}</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
columnCount: 3, // 默认列数
columnHeights: [], // 记录每列的高度
itemMargin: 25, // 元素间隙
columnData: [[], [], []], // 三列数据
}
},
computed: {
getItemStyle() {
let swiperWidth = parseInt(uni.getSystemInfoSync().windowWidth -
this.adaptScreen(35))
let swiperItem = parseInt((swiperWidth - (this.columnCount - 1) *
this.itemMargin) / this.columnCount);
return { width: swiperItem + 'px' };
},
},
mounted() {
// 调取接口
this.getMealListApi();
},
methods: {
// rpx转换
adaptScreen(rpx) {
return (uni.getSystemInfoSync().windowWidth * Number.parseInt(rpx)) / 750
},
// 获取最小高度的列索引
getMinHeightColumnIndex() {
let minHeight = this.columnHeights[0];
let minIndex = 0;
for (let i = 1; i < this.columnCount; i++) {
if (this.columnHeights[i] < minHeight) {
minHeight = this.columnHeights[i];
minIndex = i;
}
}
return minIndex;
},
// 调取接口
getMealListApi() {
// 这里调后端接口 将数据复制给 this.mealList
// 下面的数据为自己造的假数据,实战中应调取接口
this.mealList = [
{
typeName: '水果',
list: [
{ code: 1, name: '苹果' },
{ code: 2, name: '梨' },
{ code: 3, name: '草莓' },
{ code: 4, name: '樱桃' },
{ code: 5, name: '葡萄' },
],
},
{
typeName: '饮料',
list: [
{ code: 6, name: '可乐' },
{ code: 7, name: '雪碧' },
{ code: 8, name: '橙汁' },
{ code: 9, name: '王老吉' },
{ code: 10, name: '东鹏特饮' },
{ code: 11, name: '红牛' },
{ code: 12, name: '椰汁' },
],
},
{
typeName: '维生素',
list: [
{ code: 13, name: '维生素A' },
{ code: 14, name: '维生素B' },
{ code: 15, name: '维生素C' },
{ code: 16, name: '维生素D' },
],
},
{
typeName: '书本',
list: [
{ code: 17, name: '语文书' },
{ code: 18, name: '数学书' },
{ code: 19, name: '英语书' },
],
},
{
typeName: '笔记本',
list: [
{ code: 20, name: '小笔记本' },
{ code: 21, name: '大笔记本' },
],
},
{
typeName: '笔',
list: [
{ code: 22, name: '铅笔' },
{ code: 23, name: '钢笔' },
{ code: 24, name: '写字笔' },
{ code: 25, name: '彩色笔' },
{ code: 26, name: '水笔' },
{ code: 27, name: '水墨笔' },
{ code: 28, name: '签字笔' },
],
},
{
typeName: '棋子',
list: [
{ code: 29, name: '小棋子' },
],
},
{
typeName: '风扇',
list: [
{ code: 30, name: '小风扇' },
],
},
];
this.columnData = [[], [], []];
this.columnHeights = new Array(this.columnCount).fill(0);
this.mealList.forEach((items) => {
const columnIndex = this.getMinHeightColumnIndex();
console.log(columnIndex);
const columnHeight = this.columnHeights[columnIndex];
const newItemHeight = (items.list.length + 1);
this.columnHeights[columnIndex] = columnHeight + newItemHeight;
this.columnData[columnIndex].push(items);
console.log(this.columnData);
});
},
}
}
</script>
<style scoped lang="scss">
page {
background: #E2EBF0;
}
.home {
display: flex;
flex-direction: column;
.homeBox {
height: calc(100vh - 15rpx);
position: relative;
.contentBox {
width: 100%;
height: 100%;
margin-top: 4rpx;
padding-left: 10rpx;
padding-right: 6rpx;
box-sizing: border-box;
.mainContent {
width: 100%;
height: 100%;
background: linear-gradient(90deg, #E7EEF6 0%, #EEF4F7 100%);
box-shadow: -4rpx -4rpx 8rpx 0rpx rgba(252, 253, 254, 1), 4rpx 4rpx 8rpx 0rpx rgba(215, 225, 235, 1);
border-radius: 6rpx;
.swiperTable {
width: 100%;
// height: 100%;
display: flex;
justify-content: space-between;
padding: 10rpx;
box-sizing: border-box;
.columnDataBox {
margin-bottom: 5rpx;
text-align: center;
font-size: 8rpx;
.tableTitle {
border-top-left-radius: 4rpx;
border-top-right-radius: 4rpx;
background-color: #01b6fd;
border-left: 1rpx solid #01b6fd;
border-right: 1rpx solid #01b6fd;
border-bottom: 1rpx solid #01b6fd;
height: 20rpx;
line-height: 20rpx;
font-weight: bold;
color: #fff;
}
.tableContent {
// border: 1px solid #01b6fd;
border-left: 1rpx solid #01b6fd;
border-right: 1rpx solid #01b6fd;
border-bottom: 1rpx solid #01b6fd;
height: 18rpx;
line-height: 18rpx;
font-weight: bold;
}
}
}
}
}
}
}
</style>
最终实现的效果图