<template>
|
<view class="wrapper">
|
|
|
<view style="height: 100rpx"></view>
|
<!-- 内容区域 -->
|
<scroll-view scroll-y class="content" style="height: 40vh;" @scrolltolower="loadMore" :lower-threshold="100">
|
<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 === 'image'" :src="item.url" mode="widthFix" class="media" @load="imageLoad" :data-item="item"
|
:style="{ height: item.height + 'px' }" />
|
|
<!-- 视频类型 -->
|
<video v-if="item.type === 'video'" :src="item.url" class="media" controls :poster="item.poster" :data-item="item"
|
@play="handleVideoPlay" :style="{ height: item.height + 'px' }"></video>
|
|
<!-- 文字类型 -->
|
<view v-if="item.type === 'text'" class="text-content">
|
<text class="title">{{ item.cover }}</text>
|
</view>
|
<text class="title">{{ item.title }}</text>
|
|
</view>
|
</view>
|
</view>
|
<!-- <view style="height: 150rpx;"></view> -->
|
<!-- 改进的加载更多提示 -->
|
<view class="load-more">
|
<u-loadmore v-if="mockData.length > 0" :status="loading ? 'loading' : noMore ? 'nomore' : 'loadmore'"
|
:load-text="{
|
loadmore: '上拉加载更多',
|
loading: '正在加载',
|
nomore: '没有更多了'
|
}" />
|
</view>
|
<view style="height:150rpx">
|
|
</view>
|
</scroll-view>
|
|
|
|
</view>
|
</template>
|
|
<script>
|
import {
|
changeCollect
|
} from '@/api/collect.js'
|
import {
|
getFilePreviewUrl
|
} from '@/api/common.js'
|
import UButton from '@/uview-components/uview-ui/components/u-button/u-button.vue';
|
import UImage from '@/uview-components/uview-ui/components/u-image/u-image.vue';
|
import ULoadmore from '@/uview-components/uview-ui/components/u-loadmore/u-loadmore.vue'
|
import {
|
getActivityReportList,
|
} from '@/api/activity.js';
|
export default {
|
components: {
|
UImage,
|
UButton,
|
ULoadmore
|
},
|
data() {
|
return {
|
columns: [
|
[],
|
[]
|
], // 双列布局
|
mockData: [],
|
colHeight: [0, 0], // 记录各列高度
|
baseImageHeight: 300, // 图片基础高度
|
baseVideoHeight: 350, // 视频基础高度
|
baseTextHeight: 120, // 文字基础高度
|
query: {
|
pageNumber: 1,
|
pageSize: 10,
|
},
|
loading: false, // 是否正在加载
|
noMore: false, // 是否没有更多数据
|
total: 0 // 总数据量
|
};
|
},
|
onLoad() {
|
this.getActivityList();
|
},
|
methods: {
|
/**
|
* 下拉刷新时
|
*/
|
onPullDownRefresh() {
|
this.query.pageNumber = 1; // 重置页码
|
this.noMore = false;
|
this.mockData = []; // 清空数据
|
this.getActivityList();
|
},
|
loadMore() {
|
|
// 显示加载状态
|
this.loading = true;
|
|
// 延迟执行让UI有反应时间
|
setTimeout(() => {
|
this.query.pageNumber += 1;
|
this.getActivityList();
|
}, 300);
|
},
|
async getActivityList() {
|
|
try {
|
|
const res = await getActivityReportList(this.query);
|
this.loading = false;
|
if (res.statusCode === 200) {
|
const newData = res.data.data.map(value => ({
|
id: value.id,
|
type: value.coverType,
|
cover: value.cover,
|
height: value.coverType === 'image' ? this.baseImageHeight : value.coverType ===
|
'video' ? this.baseVideoHeight : this.baseTextHeight,
|
title: value.activityName,
|
content: value.activityContent,
|
poster: '',
|
url: value.url
|
}));
|
|
// 更新总数据量
|
this.total = res.data.total || 0;
|
|
// 追加或替换数据
|
this.mockData = this.query.pageNumber === 1 ?
|
newData :
|
[...this.mockData, ...newData];
|
|
// 判断是否还有更多数据
|
this.noMore = newData.length < this.query.pageSize ||
|
this.mockData.length >= this.total;
|
|
// 布局更新
|
this.$nextTick(() => {
|
this.layoutItems();
|
});
|
}
|
} catch (error) {
|
console.error('加载失败:', error);
|
// 失败时回退页码
|
if (this.query.pageNumber > 1) {
|
this.query.pageNumber -= 1;
|
}
|
} finally {
|
this.loading = false;
|
uni.hideLoading();
|
uni.stopPullDownRefresh();
|
}
|
},
|
// 图片加载完成回调
|
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); //获得高度更小的 放入元素
|
this.colHeight[minIndex] += item.height + 40; // 40为间距
|
});
|
},
|
// 图片加载回调
|
imageLoad(e) {
|
const {
|
height,
|
width
|
} = e.detail;
|
const ratio = height / width;
|
const item = e.currentTarget.dataset.item;
|
|
if (!item) {
|
console.error('无法获取图片项数据', e);
|
return;
|
}
|
// 重新计算实际显示高度
|
const viewWidth = uni.upx2px(345); // 将rpx转换为px
|
const viewHeight = viewWidth * ratio;
|
|
// 更新item高度
|
item.height = viewHeight;
|
|
// 重新计算列高度
|
this.recalculateColumns();
|
},
|
// 重新计算列高度
|
recalculateColumns() {
|
this.colHeight = [0, 0];
|
this.columns.forEach((column, colIndex) => {
|
column.forEach(item => {
|
this.colHeight[colIndex] += item.height + 40; // 40为间距
|
});
|
});
|
},
|
handleItemClick(item) {
|
console.log(item)
|
uni.navigateTo({
|
url: `/pages/mine/activity/detail?id=${item.id}` // 参数通过 URL 传递
|
});
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss">
|
/* 新增加载更多样式 */
|
.load-more {
|
padding: 20rpx 0;
|
text-align: center;
|
color: #999;
|
font-size: 26rpx;
|
background-color: #f7f8fa;
|
}
|
|
.btn-container {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
margin-top: 8px;
|
/* 与上方标题保持间距 */
|
}
|
|
/* 全局样式优化 */
|
.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;
|
/* 确保可以滚动 */
|
-webkit-overflow-scrolling: touch;
|
}
|
|
/* 瀑布流布局优化 */
|
.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>
|