This commit is contained in:
parent
46419e68bc
commit
9bc552cfb8
|
@ -11,6 +11,8 @@
|
|||
|
||||
<!-- 顶部搜索栏 -->
|
||||
<div class="search-bar">
|
||||
<div class="search-wrapper">
|
||||
<div class="search-box">
|
||||
<el-input
|
||||
v-model="searchQuery"
|
||||
placeholder="搜索视频..."
|
||||
|
@ -26,8 +28,14 @@
|
|||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
|
||||
<div class="search-tags">
|
||||
<div class="hot-searches">
|
||||
<span class="label">热门搜索:</span>
|
||||
<div class="hot-label">
|
||||
<el-icon><Histogram /></el-icon>
|
||||
<span>热门搜索</span>
|
||||
</div>
|
||||
<el-tag
|
||||
v-for="tag in hotSearches"
|
||||
:key="tag"
|
||||
|
@ -36,10 +44,26 @@
|
|||
class="hot-tag"
|
||||
@click="searchQuery = tag"
|
||||
>
|
||||
<el-icon><Search /></el-icon>
|
||||
{{ tag }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分类导航 -->
|
||||
<div class="category-nav">
|
||||
<div class="nav-item"
|
||||
v-for="item in videoCategories"
|
||||
:key="item.value"
|
||||
:class="{ active: currentCategory === item.value }"
|
||||
@click="currentCategory = item.value"
|
||||
>
|
||||
<el-icon><component :is="item.icon" /></el-icon>
|
||||
<span>{{ item.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 视频分类标签 -->
|
||||
<div class="category-tags">
|
||||
|
@ -123,6 +147,16 @@
|
|||
</div>
|
||||
|
||||
<div class="video-grid">
|
||||
<template v-if="isLoading">
|
||||
<div v-for="n in 8" :key="n" class="video-card loading-skeleton">
|
||||
<div class="thumbnail-wrapper"></div>
|
||||
<div class="video-info">
|
||||
<div class="title-skeleton"></div>
|
||||
<div class="meta-skeleton"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<video-card
|
||||
v-for="video in displayVideos"
|
||||
:key="video.id"
|
||||
|
@ -130,6 +164,7 @@
|
|||
@click="playVideo(video)"
|
||||
@favorite="toggleFavorite"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 分页器 -->
|
||||
|
@ -147,7 +182,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { Search, Star, VideoPlay, Calendar, Histogram as Fire, Collection, Timer, VideoCamera, Trophy } from '@element-plus/icons-vue'
|
||||
import VideoCard from '@/components/video/VideoCard.vue'
|
||||
import VideoGrid from '@/components/video/VideoGrid.vue'
|
||||
|
@ -159,6 +194,7 @@ const activeCategory = ref('recommended')
|
|||
const sortBy = ref('latest')
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(12)
|
||||
const isLoading = ref(false)
|
||||
|
||||
// 模拟数据
|
||||
const featuredVideos = ref([
|
||||
|
@ -389,10 +425,16 @@ const handleSearch = () => {
|
|||
// TODO: 实现搜索逻辑
|
||||
}
|
||||
|
||||
const handleCategoryChange = (category: string) => {
|
||||
const handleCategoryChange = async (category: string) => {
|
||||
activeCategory.value = category
|
||||
currentPage.value = 1
|
||||
isLoading.value = true
|
||||
try {
|
||||
// TODO: 加载对应分类的视频
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSort = () => {
|
||||
|
@ -446,6 +488,40 @@ const hotSearches = [
|
|||
'心理健康',
|
||||
'智能设备'
|
||||
]
|
||||
|
||||
// 视频分类
|
||||
const videoCategories = [
|
||||
{ label: '全部', value: 'all', icon: 'Grid' },
|
||||
{ label: '健康养生', value: 'health', icon: 'FirstAid' },
|
||||
{ label: '运动健身', value: 'fitness', icon: 'Position' },
|
||||
{ label: '营养饮食', value: 'diet', icon: 'Bowl' },
|
||||
{ label: '心理健康', value: 'mental', icon: 'SwitchButton' },
|
||||
{ label: '医疗保健', value: 'medical', icon: 'Stethoscope' },
|
||||
{ label: '智能设备', value: 'device', icon: 'Monitor' },
|
||||
{ label: '生活技巧', value: 'life', icon: 'House' },
|
||||
{ label: '文化娱乐', value: 'entertainment', icon: 'Film' },
|
||||
{ label: '旅游出行', value: 'travel', icon: 'Van' }
|
||||
]
|
||||
|
||||
const currentCategory = ref('all')
|
||||
|
||||
// 检测是否需要显示滚动阴影
|
||||
const hasScroll = ref(false)
|
||||
|
||||
// 监听滚动容器宽度变化
|
||||
onMounted(() => {
|
||||
const observer = new ResizeObserver(entries => {
|
||||
for (const entry of entries) {
|
||||
const { scrollWidth, clientWidth } = entry.target as HTMLElement
|
||||
hasScroll.value = scrollWidth > clientWidth
|
||||
}
|
||||
})
|
||||
|
||||
const scrollContainer = document.querySelector('.tags-container')
|
||||
if (scrollContainer) {
|
||||
observer.observe(scrollContainer)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -487,60 +563,214 @@ const hotSearches = [
|
|||
}
|
||||
|
||||
.search-bar {
|
||||
margin-bottom: 30px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.hot-searches {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
.search-wrapper {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.hot-tag {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #409EFF;
|
||||
border-color: #409EFF;
|
||||
}
|
||||
}
|
||||
.search-box {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
|
||||
:deep(.el-input__wrapper) {
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 8px;
|
||||
padding-left: 16px;
|
||||
background: #f5f7fa;
|
||||
box-shadow: none !important;
|
||||
border: 2px solid transparent;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background: #ecf5ff;
|
||||
}
|
||||
|
||||
&.is-focus {
|
||||
background: #fff;
|
||||
border-color: #409EFF;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-input__inner) {
|
||||
height: 44px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
:deep(.search-icon) {
|
||||
font-size: 18px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
:deep(.el-input-group__append) {
|
||||
padding: 0;
|
||||
|
||||
.el-button {
|
||||
border-radius: 0 8px 8px 0;
|
||||
padding: 0 24px;
|
||||
height: 44px;
|
||||
padding: 0 24px;
|
||||
font-size: 15px;
|
||||
border-radius: 0 4px 4px 0;
|
||||
|
||||
.el-icon {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.button-text {
|
||||
margin-left: 4px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-tags {
|
||||
position: relative;
|
||||
padding-left: 100px;
|
||||
}
|
||||
|
||||
.hot-searches {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.hot-label {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
|
||||
.el-icon {
|
||||
font-size: 16px;
|
||||
color: #f56c6c;
|
||||
}
|
||||
}
|
||||
|
||||
.hot-tag {
|
||||
cursor: pointer;
|
||||
padding: 0 12px;
|
||||
height: 28px;
|
||||
border-radius: 14px;
|
||||
border-color: #e4e7ed;
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
.el-icon {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #409EFF;
|
||||
border-color: #409EFF;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1);
|
||||
|
||||
.el-icon {
|
||||
color: #409EFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.search-tags {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.hot-searches {
|
||||
.hot-label {
|
||||
position: static;
|
||||
transform: none;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.category-nav {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||
margin-bottom: 24px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 12px;
|
||||
cursor: pointer;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s;
|
||||
|
||||
.el-icon {
|
||||
font-size: 18px;
|
||||
color: #606266;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #f5f7fa;
|
||||
|
||||
.el-icon {
|
||||
color: #409EFF;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
span {
|
||||
color: #409EFF;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: #ecf5ff;
|
||||
|
||||
.el-icon {
|
||||
color: #409EFF;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
span {
|
||||
color: #409EFF;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.category-nav {
|
||||
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
||||
gap: 8px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.category-tags {
|
||||
.custom-tabs {
|
||||
:deep(.el-tabs__item) {
|
||||
|
@ -677,4 +907,20 @@ const hotSearches = [
|
|||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* 添加加载动画 */
|
||||
.loading-skeleton {
|
||||
background: linear-gradient(90deg, #f2f2f2 25%, #e6e6e6 50%, #f2f2f2 75%);
|
||||
background-size: 200% 100%;
|
||||
animation: loading 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes loading {
|
||||
0% {
|
||||
background-position: 200% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: -200% 0;
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue