211 lines
4.6 KiB
Vue
211 lines
4.6 KiB
Vue
<template>
|
||
<!-- 水波纹背景 - 顶层显示 -->
|
||
<view class="bg-wrapper">
|
||
<image src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/wave_top.png" mode="widthFix" class="wave-bg wave-top" />
|
||
<image src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/images/wave_bottom.png" mode="widthFix" class="wave-bg wave-bottom" />
|
||
</view>
|
||
<!-- 固定白色块(滚动时显示) -->
|
||
<view class="hand" :style="{height : handHeight + 'rpx'}" v-show="isShow"></view>
|
||
|
||
<!-- 滚动内容区域 -->
|
||
<scroll-view
|
||
scroll-y
|
||
refresher-enabled
|
||
:refresher-triggered="isRefreshing"
|
||
refresher-default-style="none"
|
||
@refresherrefresh="onRefresh"
|
||
@scroll="handleScroll"
|
||
class="scroll-container"
|
||
>
|
||
|
||
<!-- 主内容 -->
|
||
<view class="home-page">
|
||
<!-- 骨架屏 -->
|
||
<HomeSkeleton v-if="loading" />
|
||
|
||
<!-- 实际内容 -->
|
||
<template v-else>
|
||
<BannerSwiper />
|
||
<QuickEntry />
|
||
<RecommendCourses />
|
||
<TodayRecommend />
|
||
<!-- 底部占位,给 TabBar 留出空间 -->
|
||
<view class="bottom-placeholder"></view>
|
||
</template>
|
||
</view>
|
||
</scroll-view>
|
||
|
||
<!-- TabBar 固定在底部,不参与滚动 -->
|
||
<view class="tabbar-fixed">
|
||
<TabBar />
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted } from 'vue'
|
||
import BannerSwiper from '@/components/index/BannerSwiper.vue'
|
||
import QuickEntry from '@/components/index/QuickEntry.vue'
|
||
import RecommendCourses from '@/components/index/RecommendCourses.vue'
|
||
import TodayRecommend from '@/components/index/TodayRecommend.vue'
|
||
import TabBar from '@/components/TabBar.vue'
|
||
import HomeSkeleton from '@/components/Skeleton/HomeSkeleton.vue'
|
||
|
||
const loading = ref(true)
|
||
const isShow = ref(false)
|
||
const handHeight = ref(0)
|
||
const scrollDistance = ref(0)
|
||
const isRefreshing = ref(false)
|
||
|
||
// 滚动监听
|
||
const handleScroll = (e) => {
|
||
const distance = e.detail.scrollTop
|
||
scrollDistance.value = distance
|
||
|
||
// 控制白色块显示/隐藏
|
||
isShow.value = distance > 238
|
||
}
|
||
|
||
// 下拉刷新处理
|
||
const onRefresh = async () => {
|
||
console.log('开始下拉刷新')
|
||
isRefreshing.value = true
|
||
|
||
try {
|
||
await refreshData()
|
||
isRefreshing.value = false
|
||
uni.showToast({
|
||
title: '刷新成功',
|
||
icon: 'success'
|
||
})
|
||
} catch (error) {
|
||
console.error('刷新失败', error)
|
||
isRefreshing.value = false
|
||
uni.showToast({
|
||
title: '刷新失败',
|
||
icon: 'error'
|
||
})
|
||
}
|
||
}
|
||
|
||
// 刷新数据
|
||
const refreshData = () => {
|
||
return new Promise((resolve) => {
|
||
setTimeout(() => {
|
||
console.log('数据已刷新')
|
||
resolve()
|
||
}, 1500)
|
||
})
|
||
}
|
||
|
||
onMounted(() => {
|
||
setTimeout(() => {
|
||
loading.value = false
|
||
}, 1500)
|
||
// 获取胶囊按钮高度
|
||
const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
|
||
const navTotalHeight = menuButtonInfo.top + menuButtonInfo.height
|
||
handHeight.value = navTotalHeight * 2
|
||
})
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
/* 背景包装器 - 固定在最底层 */
|
||
.bg-wrapper {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
z-index: 1;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.wave-bg {
|
||
position: fixed;
|
||
left: 0;
|
||
width: 100%;
|
||
pointer-events: none;
|
||
opacity: 0.6;
|
||
}
|
||
|
||
.wave-top {
|
||
top: 0;
|
||
opacity: 0.5;
|
||
}
|
||
|
||
.wave-bottom {
|
||
bottom: 100rpx;
|
||
opacity: 0.35;
|
||
}
|
||
|
||
/* 滚动容器 */
|
||
.scroll-container {
|
||
position: relative;
|
||
z-index: 1;
|
||
height: 100vh;
|
||
width: 100%;
|
||
// background: linear-gradient(180deg, #D6EEF8 0%, #E4F2FA 15%, #EEF6FB 30%, #F5FAFD 50%, #FAFCFE 70%, #FFFFFF 100%);
|
||
}
|
||
|
||
/* 主内容区域 */
|
||
.home-page {
|
||
min-height: 100vh;
|
||
padding-bottom: 160rpx; /* 为 TabBar 留出空间 */
|
||
}
|
||
|
||
/* 固定白色块 */
|
||
.hand {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
z-index: 100;
|
||
background-color: white;
|
||
width: 100%;
|
||
}
|
||
|
||
/* 固定 TabBar */
|
||
.tabbar-fixed {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 20;
|
||
background-color: transparent;
|
||
}
|
||
|
||
.bottom-placeholder {
|
||
height: 120rpx; /* 调整高度,避免内容被 TabBar 遮挡 */
|
||
}
|
||
|
||
/* 其他样式保持不变 */
|
||
.glow {
|
||
position: absolute;
|
||
border-radius: 50%;
|
||
pointer-events: none;
|
||
z-index: 0;
|
||
}
|
||
|
||
.glow-1 {
|
||
width: 400rpx;
|
||
height: 400rpx;
|
||
top: 60rpx;
|
||
right: -100rpx;
|
||
background: radial-gradient(circle, rgba(160, 210, 235, 0.35) 0%, transparent 70%);
|
||
}
|
||
|
||
.glow-2 {
|
||
width: 300rpx;
|
||
height: 300rpx;
|
||
top: 500rpx;
|
||
left: -80rpx;
|
||
background: radial-gradient(circle, rgba(180, 220, 240, 0.3) 0%, transparent 70%);
|
||
}
|
||
|
||
.glow-3 {
|
||
width: 250rpx;
|
||
height: 250rpx;
|
||
top: 900rpx;
|
||
right: -60rpx;
|
||
background: radial-gradient(circle, rgba(170, 215, 238, 0.25) 0%, transparent 70%);
|
||
}
|
||
</style> |