<template>
|
<view class="wrapper">
|
<u-navbar :is-back="true" title="活动">
|
</u-navbar>
|
<!-- 内容区域 -->
|
<scroll-view scroll-y class="content" :style="{ paddingBottom: safeAreaInsets.bottom + 'px' }">
|
<view class="waterfall">
|
<view class="column" v-for="(column, index) in columns" :key="index">
|
<!-- 遍历每列内容 -->
|
<view class="item" v-for="(item, idx) in column" :key="item.id" @click="handleItemClick(item)">
|
<!-- 图片类型 -->
|
<image v-if="item.type === '图片'" :src="item.content" mode="widthFix" class="media"
|
@load="imageLoad" :data-item="item" />
|
|
<!-- 视频类型 -->
|
<video v-if="item.type === '视频'" :src="item.content" class="media" controls
|
:poster="item.poster" @play="handleVideoPlay"></video>
|
|
<!-- 文字类型 -->
|
<view v-if="item.type === '文字'" class="text-content">
|
<text class="title">{{ item.cover }}</text>
|
</view>
|
<text class="title">{{ item.title }}</text>
|
</view>
|
</view>
|
</view>
|
</scroll-view>
|
|
|
|
<custom-tabbar bgColor="#ffffff" selected="activity"></custom-tabbar>
|
|
|
|
</view>
|
|
|
</template>
|
|
<script>
|
import {
|
getActivityReportList,
|
} from '@/api/activity.js';
|
export default {
|
data() {
|
return {
|
columns: [
|
[],
|
[]
|
], // 双列布局
|
mockData: [],
|
colHeight: [0, 0], // 记录各列高度
|
|
};
|
},
|
onLoad() {
|
this.getActivityList();
|
//获得userId
|
},
|
methods: {
|
/**
|
* 下拉刷新时
|
*/
|
onPullDownRefresh() {
|
this.getActivityList();
|
},
|
getActivityList() {
|
uni.showLoading({
|
title: '加载中'
|
});
|
const mock = [];
|
getActivityReportList().then(res => {
|
uni.hideLoading();
|
if (res.statusCode === 200) {
|
for (const value of res.data.data) {
|
const type = value.coverType;
|
const baseHeight = type === '文字' ? 120 : 350;
|
mock.push({
|
id: value.id,
|
type: type,
|
cover: value.cover,
|
height: baseHeight,
|
title: value.activityName,
|
content: value.activityContent,
|
poster: '',
|
});
|
}
|
}
|
this.mockData = mock;
|
this.layoutItems();
|
})
|
},
|
// 图片加载完成回调
|
layoutItems() {
|
this.columns = [
|
[],
|
[]
|
];
|
this.colHeight = [0, 0];
|
|
this.mockData.forEach(item => {
|
const minIndex = this.colHeight.indexOf(Math.min(...this.colHeight));
|
this.columns[minIndex].push(item);
|
|
// 文字类型不需要计算图片高度
|
if (item.type !== 'text') {
|
this.colHeight[minIndex] += item.height + 40; // 40为间距
|
} else {
|
// 文字类型固定高度计算(根据字体大小和行数)
|
const lineHeight = 40; // 假设每行40rpx
|
const lines = Math.ceil(uni.getSystemInfoSync().windowWidth / 345 * 0.8); // 响应式行数
|
this.colHeight[minIndex] += lineHeight * lines + 40;
|
}
|
});
|
console.log(this.colHeight)
|
},
|
// 图片加载回调
|
imageLoad(e) {
|
const {
|
height,
|
width
|
} = e.detail;
|
const ratio = height / width;
|
const item = e.currentTarget.dataset.item;
|
|
// 重新计算实际显示高度
|
const viewWidth = 345;
|
const viewHeight = viewWidth * ratio;
|
const index = this.columns[0].findIndex(i => i.id === item.id) ||
|
this.columns[1].findIndex(i => i.id === item.id);
|
|
if (index !== -1) {
|
const colIndex = this.colHeight[0] < this.colHeight[1] ? 0 : 1;
|
this.colHeight[colIndex] -= item.height;
|
this.colHeight[colIndex] += viewHeight;
|
item.height = viewHeight;
|
}
|
},
|
handleItemClick(item) {
|
console.log(item)
|
uni.navigateTo({
|
url: `/pages/mine/activity/detail?id=${item.id}` // 参数通过 URL 传递
|
});
|
|
}
|
},
|
}
|
</script>
|
|
<style lang="scss">
|
/* 全局样式优化 */
|
.wrapper {
|
height: 100vh;
|
display: flex;
|
flex-direction: column;
|
background-color: #f7f8fa;
|
}
|
|
/* 导航栏优化 */
|
.u-navbar {
|
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
}
|
|
/* 内容区域优化 */
|
.content {
|
flex: 1;
|
overflow: hidden;
|
padding: 0 20rpx;
|
box-sizing: border-box;
|
}
|
|
/* 瀑布流布局优化 */
|
.waterfall {
|
display: flex;
|
padding: 20rpx 0;
|
gap: 20rpx;
|
}
|
|
.column {
|
flex: 1;
|
display: flex;
|
flex-direction: column;
|
gap: 20rpx;
|
}
|
|
/* 卡片项优化 */
|
.item {
|
background: #fff;
|
border-radius: 16rpx;
|
overflow: hidden;
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
|
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
&:active {
|
transform: scale(0.98);
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.12);
|
}
|
}
|
|
/* 媒体内容样式 */
|
.media {
|
width: 100%;
|
display: block;
|
border-radius: 16rpx 16rpx 0 0;
|
background-color: #f5f5f5;
|
|
&[mode="widthFix"] {
|
height: auto;
|
}
|
}
|
|
/* 视频特殊样式 */
|
video.media {
|
object-fit: cover;
|
}
|
|
/* 文字内容样式 */
|
.text-content {
|
padding: 24rpx;
|
background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
|
min-height: 160rpx;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
|
.title {
|
color: #fff;
|
font-size: 32rpx;
|
font-weight: 500;
|
line-height: 1.4;
|
text-align: center;
|
display: -webkit-box;
|
-webkit-box-orient: vertical;
|
-webkit-line-clamp: 3;
|
overflow: hidden;
|
}
|
}
|
|
/* 标题样式优化 */
|
.title {
|
padding: 20rpx 24rpx;
|
font-size: 28rpx;
|
color: #333;
|
line-height: 1.5;
|
display: -webkit-box;
|
-webkit-box-orient: vertical;
|
-webkit-line-clamp: 2;
|
overflow: hidden;
|
font-weight: 500;
|
|
&:not(.text-content .title) {
|
border-top: 1rpx solid #f0f0f0;
|
}
|
}
|
|
/* 加载动画 */
|
@keyframes fadeInUp {
|
from {
|
opacity: 0;
|
transform: translateY(20rpx);
|
}
|
to {
|
opacity: 1;
|
transform: translateY(0);
|
}
|
}
|
|
.item {
|
animation: fadeInUp 0.4s ease forwards;
|
opacity: 0;
|
|
@for $i from 1 through 10 {
|
&:nth-child(#{$i}) {
|
animation-delay: $i * 0.05s;
|
}
|
}
|
}
|
|
/* 空状态样式 */
|
.empty-state {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
height: 60vh;
|
text-align: center;
|
|
image {
|
width: 240rpx;
|
opacity: 0.6;
|
margin-bottom: 30rpx;
|
}
|
|
text {
|
color: #c0c4cc;
|
font-size: 28rpx;
|
}
|
}
|
</style>
|