214 lines
5.0 KiB
Vue
214 lines
5.0 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 />
|
||
<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 windowHeight = ref(0)
|
||
// 获取整个滚动内容的高度
|
||
const scrollContentHeight = ref(0)
|
||
|
||
// 滚动监听
|
||
const handleScroll = (e) => {
|
||
const distance = e.detail.scrollTop
|
||
scrollDistance.value = distance
|
||
|
||
// 获取滚动容器的高度(可视区域高度)
|
||
const scrollViewHeight = e.detail.scrollHeight
|
||
scrollContentHeight.value = scrollViewHeight
|
||
|
||
// 计算滚动百分比
|
||
// 滚动百分比 = 当前滚动距离 / (内容总高度 - 可视区域高度) * 100
|
||
const maxScrollDistance = scrollContentHeight.value - windowHeight.value
|
||
let scrollPercent = 0
|
||
|
||
if (maxScrollDistance > 0) {
|
||
scrollPercent = (distance / maxScrollDistance) * 100
|
||
}
|
||
|
||
console.log(`滚动距离: ${distance}, 滚动百分比: ${scrollPercent.toFixed(2)}%`)
|
||
|
||
// 当滚动超过 10% 时显示白色块(你可以调整这个百分比)
|
||
const SHOW_THRESHOLD = 40 // 10% 的阈值,可以根据需要调整
|
||
isShow.value = scrollPercent > SHOW_THRESHOLD
|
||
}
|
||
|
||
// 下拉刷新处理
|
||
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.5
|
||
|
||
// 获取可视窗口高度
|
||
uni.getSystemInfo({
|
||
success: (res) => {
|
||
windowHeight.value = res.windowHeight
|
||
console.log('可视窗口高度:', windowHeight.value)
|
||
}
|
||
})
|
||
|
||
// 延迟获取滚动内容高度(确保DOM已渲染)
|
||
setTimeout(() => {
|
||
const query = uni.createSelectorQuery().in(this)
|
||
query.select('.home-page').boundingClientRect(data => {
|
||
if (data) {
|
||
scrollContentHeight.value = data.height
|
||
console.log('内容总高度:', scrollContentHeight.value)
|
||
}
|
||
}).exec()
|
||
}, 500)
|
||
})
|
||
</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%;
|
||
}
|
||
|
||
/* 主内容区域 */
|
||
.home-page {
|
||
min-height: 100vh;
|
||
padding-bottom: 160rpx;
|
||
}
|
||
|
||
/* 固定白色块 */
|
||
.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: 1000;
|
||
background-color: transparent;
|
||
}
|
||
|
||
.bottom-placeholder {
|
||
height: 120rpx;
|
||
}
|
||
</style> |