hookehuyr

refactor(StudyDetailPage): 重构页面布局以优化用户体验

将视频播放和标签页区域固定,滚动区域独立,提升页面交互流畅性。添加标签页切换时的平滑滚动效果,优化用户浏览体验。
......@@ -4,54 +4,64 @@
-->
<template>
<div class="study-detail-page bg-gradient-to-b from-green-50/70 to-white/90 min-h-screen pb-20">
<div v-if="course" class="flex flex-col">
<!-- 视频播放区域 -->
<div class="w-full bg-black relative">
<!-- 视频封面和播放按钮 -->
<div v-if="!isPlaying" class="relative w-full" style="aspect-ratio: 16/9;">
<img :src="course.cover" :alt="course.title" class="w-full h-full object-cover" />
<div class="absolute inset-0 flex items-center justify-center cursor-pointer" @click="startPlay">
<div
class="w-24 h-24 rounded-full bg-black/50 flex items-center justify-center hover:bg-black/70 transition-colors">
<font-awesome-icon icon="circle-play" class="text-5xl text-white" style="font-size: 3rem;" />
<div v-if="course" class="flex flex-col h-screen">
<!-- 固定区域:视频播放和标签页 -->
<div class="fixed top-0 left-0 right-0 z-10 top-wrapper">
<!-- 视频播放区域 -->
<div class="w-full bg-black relative">
<!-- 视频封面和播放按钮 -->
<div v-if="!isPlaying" class="relative w-full" style="aspect-ratio: 16/9;">
<img :src="course.cover" :alt="course.title" class="w-full h-full object-cover" />
<div class="absolute inset-0 flex items-center justify-center cursor-pointer"
@click="startPlay">
<div
class="w-24 h-24 rounded-full bg-black/50 flex items-center justify-center hover:bg-black/70 transition-colors">
<font-awesome-icon icon="circle-play" class="text-5xl text-white"
style="font-size: 3rem;" />
</div>
</div>
</div>
<!-- 视频播放器 -->
<VideoPlayer v-show="isPlaying" ref="videoPlayerRef" :video-url="course.videoUrl" :autoplay="false"
@onPlay="handleVideoPlay" @onPause="handleVideoPause" />
</div>
<!-- 标签页区域 -->
<div class="px-4 py-3 bg-white">
<van-tabs v-model:active="activeTab" sticky animated swipeable shrink @change="handleTabChange">
<van-tab title="介绍" name="intro">
</van-tab>
<van-tab :title-style="{ 'min-width': '50%' }" name="comments">
<template #title>评论(999)</template>
</van-tab>
</van-tabs>
</div>
<!-- 视频播放器 -->
<VideoPlayer v-show="isPlaying" ref="videoPlayerRef" :video-url="course.videoUrl" :autoplay="false"
@onPlay="handleVideoPlay" @onPause="handleVideoPause" />
</div>
<!-- 标签页区域 -->
<div class="px-4 py-3">
<van-tabs v-model:active="activeTab" sticky animated swipeable>
<!-- 介绍标签页 -->
<van-tab title="介绍" name="intro">
<div class="py-4">
<h1 class="text-xl font-bold mb-2">{{ course.title }}</h1>
<div class="text-gray-500 text-sm">
{{ course.studyCount || 0 }}次学习
</div>
</div>
</van-tab>
<!-- 评论标签页 -->
<van-tab title="评论" :title-style="{ 'min-width': '50%' }" name="comments">
<div class="py-4 space-y-4">
<div v-for="comment in comments" :key="comment.id"
class="bg-white rounded-lg p-4 shadow-sm">
<div class="flex items-center mb-2">
<img :src="comment.avatar" class="w-8 h-8 rounded-full mr-2" />
<div>
<div class="font-medium">{{ comment.username }}</div>
<div class="text-gray-500 text-xs">{{ comment.time }}</div>
</div>
</div>
<div class="text-gray-700">{{ comment.content }}</div>
<!-- 滚动区域:介绍和评论内容 -->
<div class="overflow-y-auto flex-1" :style="{paddingTop: topWrapperHeight, height: 'calc(100vh - ' + topWrapperHeight + ')'}">
<div id="intro" class="py-4 px-4">
<h1 class="text-lg font-bold mb-2">{{ course.title }}</h1>
<div class="text-gray-500 text-sm flex items-center gap-2">
<span>{{ course.date }}</span>
<span class="text-gray-300">|</span>
<span>{{ course.studyCount || 0 }}次学习</span>
</div>
</div>
<div class="h-2 bg-gray-100"></div>
<div id="comment" class="py-4 px-4 space-y-4">
<div v-for="comment in comments" :key="comment.id" class="bg-white rounded-lg p-4 shadow-sm">
<div class="flex items-center mb-2">
<img :src="comment.avatar" class="w-8 h-8 rounded-full mr-2" />
<div>
<div class="font-medium">{{ comment.username }}</div>
<div class="text-gray-500 text-xs">{{ comment.time }}</div>
</div>
</div>
</van-tab>
</van-tabs>
<div class="text-gray-700">{{ comment.content }}</div>
</div>
</div>
</div>
<!-- 底部操作栏 -->
......@@ -126,9 +136,15 @@ const comments = ref([
// 设置页面标题
useTitle('学习详情');
// 获取课程详情
const topWrapperHeight = ref(0);
onMounted(() => {
nextTick(() => {
const topWrapper = document.querySelector('.top-wrapper');
if (topWrapper) {
topWrapperHeight.value = topWrapper.clientHeight + 'px';
}
})
const courseId = route.params.id;
if (courseId) {
// TODO: 这里需要替换为实际的API调用
......@@ -141,7 +157,8 @@ onMounted(() => {
studyTime: 3600,
type: '视频课程',
studyCount: 1896,
cover: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg'
cover: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg',
date: '2024-12-04'
};
}
})
......@@ -160,4 +177,20 @@ const submitComment = () => {
newComment.value = '';
};
// 处理标签页切换
const handleTabChange = (name) => {
nextTick(() => {
const element = document.getElementById(name === 'intro' ? 'intro' : 'comment');
if (element && container) {
const topOffset = element.offsetTop - parseInt(topWrapperHeight.value);
window.scrollTo({
top: topOffset,
behavior: 'smooth'
});
}
})
};
</script>
......