<template>
|
<view class="search-page">
|
<!-- 搜索区域 -->
|
<view class="search-bar">
|
<input
|
class="search-input"
|
v-model="searchQuery.keyword"
|
placeholder="请输入搜索关键词"
|
placeholder-class="placeholder-style"
|
@confirm="handleSearch"
|
/>
|
<button class="search-btn" @click="handleSearch">搜索</button>
|
</view>
|
|
<!-- 瀑布流视频列表 -->
|
<view class="waterfall-container">
|
<view class="waterfall-left">
|
<view
|
class="video-item"
|
v-for="(item, index) in leftList"
|
:key="item.id"
|
@click="playVideo(item)"
|
>
|
<image class="video-cover" :src="item.coverUrl" mode="widthFix"></image>
|
<view class="video-info">
|
<text class="video-title">{{item.title}}</text>
|
<view class="video-tags">
|
<text class="tag" v-for="(tag, i) in item.tagList" :key="i">{{tag.tagName}}</text>
|
</view>
|
<view class="video-stats">
|
<text class="like-count">❤️ {{item.thumbsUpNum}}</text>
|
</view>
|
</view>
|
</view>
|
</view>
|
|
<view class="waterfall-right">
|
<view
|
class="video-item"
|
v-for="(item, index) in rightList"
|
:key="item.id"
|
@click="playVideo(item)"
|
>
|
<image class="video-cover" :src="item.coverUrl" mode="widthFix"></image>
|
<view class="video-info">
|
<text class="video-title">{{item.title}}</text>
|
<view class="video-tags">
|
<text class="tag" v-for="(tag, i) in item.tagList" :key="i">{{tag.tagName}}</text>
|
</view>
|
<view class="video-stats">
|
<text class="like-count">❤️ {{item.thumbsUpNum}}</text>
|
</view>
|
</view>
|
</view>
|
</view>
|
</view>
|
|
<!-- 加载更多提示 -->
|
<view class="load-more" v-if="loading">
|
<text>加载中...</text>
|
</view>
|
<view class="load-more" v-if="noMore">
|
<text>没有更多了</text>
|
</view>
|
</view>
|
</template>
|
|
<script>
|
import {videoSearch} from "@/api/video.js"
|
export default {
|
data() {
|
return {
|
videoList: [], // 所有视频数据
|
leftList: [], // 左侧列视频
|
rightList: [], // 右侧列视频
|
searchQuery: {
|
keyword: '',
|
pageNumber: 1, // 虽然es是从第0页开始的,但是为了在跳转到video-play页之后和其它类型的查询保持一致,这里从1开始,后端默认-1
|
pageSize: 10
|
},
|
loading: false,
|
noMore: false
|
}
|
},
|
onLoad() {
|
// 初始加载一些数据
|
this.loadVideos();
|
},
|
methods: {
|
handleSearch() {
|
if (!this.searchQuery.keyword.trim()) {
|
uni.showToast({
|
title: '请输入搜索关键词',
|
icon: 'none'
|
});
|
return;
|
}
|
|
// 重置数据
|
this.searchQuery.pageNumber = 1;
|
this.videoList = [];
|
this.leftList = [];
|
this.rightList = [];
|
this.noMore = false;
|
|
// 执行搜索
|
this.loadVideos();
|
},
|
|
async loadVideos() {
|
if (this.loading || this.noMore) return;
|
|
this.loading = true;
|
uni.showLoading({ title: '加载中' });
|
|
try {
|
videoSearch(this.searchQuery).then(res => {
|
if (this.searchQuery.pageNumber === 1) {
|
this.videoList = res.data.data
|
} else {
|
this.videoList = [
|
...this.videoList,
|
...res.data.data.filter(
|
(newItem) => !this.videoList.some((oldItem) => oldItem.id === newItem.id)
|
),
|
];
|
}
|
// 分配瀑布流
|
this.distributeWaterfall();
|
|
if (res.data.data.length < this.searchQuery.pageSize) {
|
this.noMore = true
|
} else {
|
this.searchQuery.pageNumber += 1
|
}
|
})
|
} catch (error) {
|
console.error('加载视频失败:', error);
|
uni.showToast({
|
title: '加载失败',
|
icon: 'none'
|
});
|
} finally {
|
this.loading = false;
|
uni.hideLoading();
|
}
|
},
|
|
// 分配瀑布流左右列
|
distributeWaterfall() {
|
let leftHeight = this.getColumnHeight(this.leftList);
|
let rightHeight = this.getColumnHeight(this.rightList);
|
|
// 从当前videoList中未分配的开始
|
const startIndex = this.leftList.length + this.rightList.length;
|
|
for (let i = startIndex; i < this.videoList.length; i++) {
|
const item = this.videoList[i];
|
item["index"] = i;
|
// 计算这个item的大概高度(根据封面比例)
|
const itemHeight = 200 + Math.random() * 50; // 简单模拟高度差异
|
|
if (leftHeight <= rightHeight) {
|
this.leftList.push(item);
|
leftHeight += itemHeight;
|
} else {
|
this.rightList.push(item);
|
rightHeight += itemHeight;
|
}
|
}
|
},
|
|
// 获取列的高度(简单实现)
|
getColumnHeight(list) {
|
return list.length * 250; // 假设每个item大约250高度
|
},
|
|
// 播放视频
|
playVideo(item) {
|
const searchPlayInfo = {
|
videoList: this.videoList,
|
nomore: this.noMore,
|
pageNumber: this.searchQuery.pageNumber,
|
playIndex: item.index,
|
keyword: this.searchQuery.keyword
|
}
|
uni.setStorageSync("searchPlayInfo", searchPlayInfo)
|
uni.navigateTo({
|
url: `/pages/video/video-play?videoFrom=search`
|
});
|
},
|
},
|
|
// 上拉加载更多
|
onReachBottom() {
|
this.loadVideos();
|
}
|
}
|
</script>
|
|
<style scoped>
|
.search-page {
|
padding: 20rpx;
|
}
|
|
.search-bar {
|
display: flex;
|
align-items: center;
|
margin-bottom: 20rpx;
|
}
|
|
.search-input {
|
flex: 1;
|
height: 70rpx;
|
padding: 0 20rpx;
|
background-color: #efefef;
|
border-radius: 35rpx;
|
font-size: 28rpx;
|
}
|
|
.placeholder-style {
|
color: #999;
|
}
|
|
.search-btn {
|
width: 120rpx;
|
height: 70rpx;
|
margin-left: 20rpx;
|
line-height: 70rpx;
|
font-size: 28rpx;
|
background-color: #07c160;
|
color: white;
|
border-radius: 35rpx;
|
}
|
|
.waterfall-container {
|
display: flex;
|
justify-content: space-between;
|
}
|
|
.waterfall-left,
|
.waterfall-right {
|
width: 48%;
|
}
|
|
.video-item {
|
margin-bottom: 20rpx;
|
background: #fff;
|
border-radius: 12rpx;
|
overflow: hidden;
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
}
|
|
.video-cover {
|
width: 100%;
|
display: block;
|
}
|
|
.video-info {
|
padding: 16rpx;
|
}
|
|
.video-title {
|
font-size: 28rpx;
|
color: #333;
|
display: -webkit-box;
|
-webkit-box-orient: vertical;
|
-webkit-line-clamp: 2;
|
overflow: hidden;
|
line-height: 1.4;
|
}
|
|
.video-tags {
|
margin-top: 10rpx;
|
display: flex;
|
flex-wrap: wrap;
|
gap: 20rpx;
|
}
|
|
.tag {
|
font-size: 24rpx;
|
color: #07c160;
|
background: #e8f5e9;
|
border-radius: 20rpx;
|
flex: 1 1 calc(50% - 20rpx); /* 考虑gap的宽度 */
|
min-width: calc(50% - 20rpx);
|
max-width: 100%;
|
}
|
|
.video-stats {
|
margin-top: 10rpx;
|
display: flex;
|
align-items: center;
|
}
|
|
.like-count {
|
font-size: 24rpx;
|
color: #666;
|
}
|
|
.load-more {
|
text-align: center;
|
padding: 20rpx;
|
font-size: 24rpx;
|
color: #999;
|
}
|
</style>
|