1、增加loading组件,用于预加载scroll-view的背景图片,然后使得scroll-view进行隐藏的滚动到首页
2、调整首页滚动逻辑,使得可以完全屏蔽滚动;同时修改向上滚动逻辑
This commit is contained in:
Wenzhe 2026-02-03 23:44:05 +08:00
parent ab75f0056c
commit e3d0ffe1e6
2 changed files with 325 additions and 160 deletions

View File

@ -0,0 +1,216 @@
<script setup>
import { ref, onMounted, computed } from 'vue'
//
const props = defineProps({
//
visible: {
type: Boolean,
default: true
}
})
//
const emit = defineEmits(['loaded', 'start'])
//
const loadingProgress = ref(0)
//
const isLoadingComplete = ref(false)
//
const showStartButton = ref(false)
// URL
const generateImageUrl = (name) => {
const url = new URL(`/static/bg/${name}.jpg`, import.meta.url)
//
return url.href
}
//
const startButtonVisible = computed(() => {
return isLoadingComplete.value && showStartButton.value
})
//
const loadImages = async () => {
//
const bgImageNames = [
'bg1',
'bg2',
'bg3',
'bg4',
'bg5',
'bg_finish',
'bg_main'
]
// URL
const bgImages = bgImageNames.map(name => generateImageUrl(name))
const totalImages = bgImages.length
let loadedImages = 0
//
for (const imagePath of bgImages) {
try {
await loadImage(imagePath)
loadedImages++
//
const progress = Math.round((loadedImages / totalImages) * 100)
loadingProgress.value = progress
// 使
await new Promise(resolve => setTimeout(resolve, 100))
} catch (error) {
console.error('加载图片失败:', imagePath, error)
// 使
loadedImages++
loadingProgress.value = Math.round((loadedImages / totalImages) * 100)
}
}
//
isLoadingComplete.value = true
loadingProgress.value = 100
// 100%
setTimeout(() => {
showStartButton.value = true
//
emit('loaded')
}, 500)
}
//
const loadImage = (src) => {
return new Promise((resolve, reject) => {
const img = new Image()
img.onload = resolve
img.onerror = reject
img.src = src
})
}
//
const handleStart = () => {
emit('start')
}
//
onMounted(() => {
loadImages()
})
</script>
<template>
<div v-if="visible" class="loading-container">
<!-- 背景图片 -->
<div class="loading-bg">
<img src="/static/loading/loading_bg.jpg" alt="加载背景" class="bg-image" />
</div>
<!-- 进度条区域 -->
<div class="progress-container">
<div class="progress-bar">
<div class="progress-fill" :style="{ width: `${loadingProgress}%` }"></div>
</div>
<div class="progress-text">{{ loadingProgress }}%</div>
</div>
<!-- 开始按钮 -->
<div v-if="startButtonVisible" class="start-button" @click="handleStart">
<img src="/static/loading/btn_start.png" alt="开始" class="start-btn-image" />
</div>
</div>
</template>
<style scoped>
.loading-container {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 9999;
}
.loading-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
}
.bg-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.progress-container {
position: absolute;
bottom: 30vh;
width: 80%;
max-width: 500rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.progress-bar {
width: 100%;
height: 20rpx;
background-color: rgba(255, 255, 255, 0.3);
border-radius: 10rpx;
overflow: hidden;
margin-bottom: 20rpx;
}
.progress-fill {
height: 100%;
background-color: #FFD700;
border-radius: 10rpx;
transition: width 0.3s ease;
}
.progress-text {
font-size: 36rpx;
font-weight: bold;
color: #FFD700;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.5);
}
.start-button {
position: absolute;
bottom: 20vh;
width: 300rpx;
height: 100rpx;
cursor: pointer;
animation: pulse 1.5s infinite;
}
.start-btn-image {
width: 100%;
height: 100%;
object-fit: contain;
}
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
}
}
</style>

View File

@ -14,6 +14,7 @@ import EndPage from './EndPage.vue'
import LotteryFormModal from './LotteryFormModal.vue'
import AICoupletForm from './AICoupletForm.vue'
import CoupletDisplay from './CoupletDisplay.vue'
import LoadingComponent from './LoadingComponent.vue'
const sceneStore = useSceneStore()
const collectionStore = useCollectionStore()
@ -52,6 +53,10 @@ const hasSubmittedUserInfo = ref(false)
const hasScrolled = ref(false)
//
const isAutoScrolling = ref(false)
//
const showLoading = ref(true)
//
const isImagesLoaded = ref(false)
//
@ -140,8 +145,95 @@ const collectedSeals = computed(() => {
}
})
//
onMounted(() => {
//
const handleLoadingComplete = () => {
isImagesLoaded.value = true
console.log('图片加载完成,准备初始化页面')
// scrollContainer
ensureScrollContainerReady()
}
// scrollContainer
const ensureScrollContainerReady = () => {
// DOM
nextTick(() => {
const checkScrollContainer = () => {
if (!scrollContainer.value) {
console.log('scrollContainer 尚未初始化,延迟重试...')
setTimeout(checkScrollContainer, 100)
return
}
const container = scrollContainer.value
console.log('scrollContainer 已初始化:', {
scrollHeight: container.scrollHeight,
clientHeight: container.clientHeight
})
// scrollHeight 0
if (container.scrollHeight === 0) {
console.log('内容尚未渲染,延迟重试...')
setTimeout(checkScrollContainer, 100)
return
}
//
isAutoScrolling.value = true
// section ID使 scroll-into-view
homeSectionId.value = 'home-section'
console.log('使用 scroll-into-view 滚动到首页')
//
activeSceneIndex.value = scenes.value.length - 1
// scroll-into-view
setTimeout(() => {
//
try {
const targetScrollTop = container.scrollHeight - container.clientHeight
if (typeof container.scrollTo === 'function') {
container.scrollTo({
top: targetScrollTop,
duration: 0
})
} else {
container.scrollTop = targetScrollTop
}
console.log('已滚动到最下方scrollTop:', container.scrollTop)
} catch (error) {
console.error('滚动失败:', error)
}
//
isAutoScrolling.value = false
// hasScrolled false
hasScrolled.value = false
console.log('scrollContainer 准备就绪hasScrolled:', hasScrolled.value)
}, 300)
}
// scrollContainer
checkScrollContainer()
})
}
//
const handleStart = () => {
//
showLoading.value = false
//
hasScrolled.value = false
console.log('点击开始按钮hasScrolled:', hasScrolled.value)
//
initPage()
}
//
const initPage = () => {
// 访
recordPageVisit({
user_agent: navigator.userAgent,
@ -163,114 +255,15 @@ onMounted(() => {
}
})
// - 使uniappscroll-view
// scroll-view @scroll
//
titleImageShown.value = true
isAutoScrolling.value = false
console.log('页面准备就绪')
}
//
const scrollToHomePage = () => {
//
isAutoScrolling.value = true
if (!scrollContainer.value) {
console.log('scrollContainer 尚未初始化')
return
}
//
const container = scrollContainer.value
console.log('scrollContainer 已初始化:', {
element: container,
scrollHeight: container.scrollHeight,
clientHeight: container.clientHeight,
scrollTop: container.scrollTop,
classList: container.classList
})
// scrollHeight0
if (container.scrollHeight === 0) {
console.log('内容尚未渲染,延迟重试...')
setTimeout(scrollToHomePage, 100)
return
}
// scenes.value.length - 1
//
const homeIndex = scenes.value.length - 1
// 1: 使 scroll-into-viewuniapp
console.log('使用 scroll-into-view 滚动到首页')
homeSectionId.value = 'home-section'
//
activeSceneIndex.value = homeIndex
//
activeSceneIndex.value = homeIndex
//
setTimeout(() => {
if (!container) {
console.log('scrollContainer 已卸载')
return
}
console.log('验证滚动结果:', {
currentScrollTop: container.scrollTop,
scrollHeight: container.scrollHeight,
clientHeight: container.clientHeight,
isAtBottom: Math.abs(container.scrollTop - (container.scrollHeight - container.clientHeight)) < 50
})
//
const isAtBottom = Math.abs(container.scrollTop - (container.scrollHeight - container.clientHeight)) < 50
if (!isAtBottom) {
console.log('滚动验证失败,使用备用方法重试...')
// 2: 使 scrollTo scrollTop
try {
const targetScrollTop = container.scrollHeight - container.clientHeight
if (typeof container.scrollTo === 'function') {
container.scrollTo({
top: targetScrollTop,
duration: 0
})
} else {
container.scrollTop = targetScrollTop
}
} catch (error) {
console.log('备用方法失败:', error)
container.scrollTop = container.scrollHeight - container.clientHeight
}
//
setTimeout(() => {
//
isPageReady.value = true
titleImageShown.value = true
//
isAutoScrolling.value = false
console.log('设置 isPageReady = true准备显示页面')
}, 50)
} else {
console.log('成功滚动到首页')
//
//
isPageReady.value = true
titleImageShown.value = true
//
isAutoScrolling.value = false
console.log('设置 isPageReady = true准备显示页面')
}
}, 300)
}
// -
setTimeout(scrollToHomePage, 800)
//
setTimeout(scrollToHomePage, 1500)
//
onMounted(() => {
console.log('SinglePageContainer 组件挂载')
})
//
@ -512,15 +505,15 @@ onUnmounted(() => {
<template>
<div class="single-page-wrapper">
<!-- 加载提示 -->
<div class="loading-hint" v-if="!isPageReady">
<div class="loading-spinner"></div>
<p>正在加载...</p>
</div>
<!-- 加载组件 -->
<LoadingComponent
v-if="showLoading"
@loaded="handleLoadingComplete"
@start="handleStart"
/>
<scroll-view
class="single-page-container"
:class="{ 'visible': isPageReady }"
ref="scrollContainer"
scroll-y="true"
scroll-with-animation="true"
@ -654,44 +647,6 @@ onUnmounted(() => {
overflow: hidden;
}
/* 加载提示样式 */
.loading-hint {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 1000;
background: rgba(253, 233, 223, 0.95);
padding: 30px 40px;
border-radius: 15px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}
.loading-spinner {
width: 40px;
height: 40px;
border: 3px solid #f3f3f3;
border-top: 3px solid #FF6B35;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 15px;
}
.loading-hint p {
color: #FF6B35;
font-size: 16px;
font-weight: 500;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.single-page-container {
position: relative;
width: 100%;
@ -699,17 +654,11 @@ onUnmounted(() => {
overflow-y: scroll; /* 改为 scroll 确保可以滚动 */
overflow-x: hidden;
-webkit-overflow-scrolling: touch; /* 启用iOS平滑滚动 */
/* 使用 visibility 而不是 opacity确保完全不可见且不可交互 */
visibility: hidden;
touch-action: pan-y; /* 允许垂直方向的触摸滚动 */
user-select: none; /* 防止触摸时文本被选中 */
}
.single-page-container.visible {
visibility: visible;
/* 添加淡入效果 */
animation: fadeIn 0.4s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; }