StudyCoursePage.vue 6.99 KB
<!--
 * @Date: 2024-01-17
 * @Description: 课程详情页面
-->
<template>
    <div class="study-course-page bg-gradient-to-b from-green-50/70 to-white/90 min-h-screen">
        <div v-if="course" class="flex flex-col h-screen">
            <!-- 固定区域:课程封面和标签页 -->
            <div class="fixed top-0 left-0 right-0 z-10 top-wrapper bg-white">
                <!-- 课程封面区域 -->
                <van-image
                    class="w-full aspect-video object-cover"
                    :src="course?.coverImage"
                    :alt="course?.title"
                />
                <div class="p-4">
                    <h1 class="text-black text-xl font-bold mb-2">{{ course?.title }}</h1>
                    <div class="flex items-center text-gray-500 text-sm">
                        <span>已更新 20期</span>
                        <span class="mx-2">|</span>
                        <span>116人订阅</span>
                    </div>
                </div>

                <div class="h-2 bg-gray-100"></div>

                <!-- 标签页区域 -->
                <div class="py-3 bg-white">
                    <van-tabs v-model:active="activeTab" sticky animated swipeable shrink @change="handleTabChange">
                        <van-tab title="详情" name="detail">
                        </van-tab>
                        <van-tab title="目录" name="catalog">
                        </van-tab>
                        <van-tab title="课程互动" name="interaction">
                        </van-tab>
                    </van-tabs>
                </div>
            </div>

            <!-- 滚动区域:详情、目录和互动内容 -->
            <div class="overflow-y-auto flex-1" :style="{paddingTop: topWrapperHeight, height: 'calc(100vh - ' + topWrapperHeight + ')'}">
                <!-- 详情区域 -->
                <div id="detail" class="py-4 px-4">
                    <div class="text-gray-700 text-sm leading-relaxed" v-html="course?.description"></div>
                    <van-empty description="暂无详情" />
                </div>

                <div class="h-2 bg-gray-100"></div>

                <!-- 目录区域 -->
                <div id="catalog" class="py-4">
                    <div class="space-y-4">
                        <div v-for="(lesson, index) in course?.lessons" :key="index" class="bg-white p-4 cursor-pointer hover:bg-gray-50 transition-colors border-b border-gray-200 relative">
                            <div v-if="lesson.progress > 0 && lesson.progress < 100" class="absolute top-2 right-2 px-2 py-1 bg-green-100 text-green-600 text-xs rounded">上次看到</div>
                            <div class="text-black text-base font-medium mb-2">{{ lesson.title }}</div>
                            <div class="flex items-center text-sm text-gray-500">
                                <span>视频</span>&nbsp;
                                <span>2024-10-22</span>
                                <span class="mx-2">|</span>
                                <span>1897次学习</span>
                                <span class="mx-2">|</span>
                                <span>已学习{{ lesson.progress }}%</span>
                            </div>
                        </div>
                    </div>
                </div>

                <div class="h-2 bg-gray-100"></div>

                <!-- 互动区域 -->
                <div id="interaction" class="py-4 px-4">
                    <div class="bg-white rounded-lg p-4 mb-4 cursor-pointer">
                        <div class="flex items-center justify-between">
                            <div class="flex items-center gap-3">
                                <van-icon size="3rem" name="calendar-o" class="text-xl text-gray-600" />
                                <div>
                                    <div class="text-base font-medium">打卡</div>
                                    <div class="text-sm text-gray-500">关联7个打卡</div>
                                </div>
                            </div>
                            <van-icon name="arrow" class="text-gray-400" />
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup>
import { ref, onMounted, nextTick, onUnmounted } from 'vue';
import { useTitle } from '@vueuse/core';

// 页面标题
useTitle('课程详情');

// 当前激活的标签页
const activeTab = ref('detail');
const topWrapperHeight = ref(0);

// 处理滚动事件
const handleScroll = () => {
    const detailElement = document.getElementById('detail');
    const catalogElement = document.getElementById('catalog');
    const interactionElement = document.getElementById('interaction');
    if (!detailElement || !catalogElement || !interactionElement) return;

    const scrollTop = window.scrollY;
    const catalogOffset = catalogElement.offsetTop - parseInt(topWrapperHeight.value);
    const interactionOffset = interactionElement.offsetTop - parseInt(topWrapperHeight.value);

    // 根据滚动位置更新activeTab
    if (scrollTop >= interactionOffset) {
        activeTab.value = 'interaction';
    } else if (scrollTop >= catalogOffset) {
        activeTab.value = 'catalog';
    } else {
        activeTab.value = 'detail';
    }
};

// 处理标签页切换
const handleTabChange = (name) => {
    nextTick(() => {
        const element = document.getElementById(name);
        if (element) {
            const topOffset = element.offsetTop - parseInt(topWrapperHeight.value);
            window.scrollTo({
                top: topOffset,
                behavior: 'smooth'
            });
        }
    });
};

onMounted(() => {
    nextTick(() => {
        const topWrapper = document.querySelector('.top-wrapper');
        if (topWrapper) {
            topWrapperHeight.value = topWrapper.clientHeight + 'px';
        }

        // 添加滚动监听
        window.addEventListener('scroll', handleScroll);
    });
});

// 在组件卸载时移除滚动监听
onUnmounted(() => {
    window.removeEventListener('scroll', handleScroll);
});

// 课程数据
const course = ref({
    title: '开学礼·止的智慧·心法老师·20241001',
    coverImage: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg',
    updateTime: '2024.01.17',
    viewCount: 1897,
    description: '这是一门关于心法的课程,帮助学员掌握止的智慧...',
    lessons: [
        {
            title: '第一课:止的基础',
            duration: '45分钟',
            progress: 100
        },
        {
            title: '第二课:止的技巧',
            duration: '50分钟',
            progress: 60
        },
        {
            title: '第三课:止的应用',
            duration: '40分钟',
            progress: 0
        }
    ]
});
</script>

<style scoped>
.study-course-page {
    min-height: 100vh;
}

.course-header {
    height: auto;
}

.course-tabs {
    background-color: #fff;
}

.course-catalog {
    background-color: #fff;
}
</style>